Index: /greenstone3/trunk/LICENSE.txt
===================================================================
--- /greenstone3/trunk/LICENSE.txt	(revision 14125)
+++ /greenstone3/trunk/LICENSE.txt	(revision 14125)
@@ -0,0 +1,350 @@
+Copyright (c) 2003 New Zealand Digital Library Project, University of Waikato
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, and distribute copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the GPL and the following conditions (where not in conflict with the GPL):
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software, as will all other notices contained in the copyrights directory.
+
+THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDER (Greenstone Digital Libraries, University of Waikato), OR THEIR STAFF BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of New Zealand Digital Library Project, University of Waikato shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the New Zealand Digital Library Project, University of Waikato. Distributed under GPL, as follows: 
+
+
+		    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: /greenstone3/trunk/README-CVS.txt
===================================================================
--- /greenstone3/trunk/README-CVS.txt	(revision 14125)
+++ /greenstone3/trunk/README-CVS.txt	(revision 14125)
@@ -0,0 +1,94 @@
+Greenstone 3 (GSDL3)
+Copyright (C) 2003 New Zealand Digital Libraries, University Of Waikato
+Greenstone3 comes with ABSOLUTELY NO WARRANTY; for details see LICENSE.txt
+This is free software, and you are welcome to redistribute it
+
+These are some extra notes for installing Greenstone from CVS. Please also read the README.txt file for general information as almost all of that applies here too.
+
+Installing Greenstone from a CVS checkout:
+---------------------------------------------------------------------
+
+Make sure the CVS executable is on your PATH.
+
+Checkout the code:
+
+cvs -d :pserver:cvs_anon@cvs.scms.waikato.ac.nz:2402/usr/local/global-cvs/gsdl-src co greenstone3
+
+Build and install:
+
+In the greenstone3 directory, edit the build.properties file (see 'Configuring your installation' in README.txt), and run 'ant prepare install'. The two targets can be run separately if you like.
+
+The 'prepare' target will download additional code (using CVS and http), so you need to be online to run it. The 'install' target can be run offline.
+
+The prepare/install targets will ask you if you accept the properties before starting.
+To suppress this prompt, use the -Dproperties.accepted=yes flag. E.g.
+ant -Dproperties.accepted=yes prepare install (from CVS), or
+To log the output, run
+ant -Dproperties.accepted=yes -logfile build.log prepare install (from CVS), or
+
+Extra Configuration notes:
+--------------------------------------------------------------
+
+Greenstone 3 uses some parts of Greenstone 2 for collection building, 
+including external packages and the Librarian Interface. These will be 
+installed during the Greenstone 3 installation process. If you do not want 
+collection building capability, please set the disable.collection.building property to true in build.properties. 
+
+
+Common install/update targets:
+---------------------------------------------------------------------
+1. Install for the first time from CVS:
+cvs co greenstone3
+cd greenstone3
+ant prepare install
+
+2. Install for the first time from CVS, mostly offline:
+[online]
+cvs co greenstone3
+cd greenstone3
+ant prepare
+[offline]
+ant install
+
+3. Install for the first time, with CVS done outside of Ant (if you have problems running CVS commands from Ant):
+cvs co -P greenstone3
+cd greenstone3
+[if you want collection building:
+cvs co -P gli
+cvs co -P gs2build
+]
+[if you didn't want collection building
+cd src/packages
+cvs co indexers
+cd ../../
+]
+[if you are on windows
+cvs co winbin
+]
+ant -Dnocvs.mode=yes prepare install (prepare needs to be online, install can be done offline)
+
+4. Updating your Greenstone installation from CVS (and reconfigure/recompile):
+cd greenstone3
+ant update
+
+5. Updating your Greenstone installation from CVS, offline:
+cd greenstone3
+[online]
+ant cvsupdate
+[offline]
+ant -Dnocvs.mode=yes update
+
+6. Updating your Greenstone installation, with CVS done outside of Ant:
+cd greenstone3
+cvs update -l
+cvs update -dP bin docs lib resources src winutil packages 
+cd web (or the path-to-tomcat/webapps/greenstone3 if have installed greenstone as a webapp in Tomcat, see Using External Tomcat section)
+cvs update -dP 
+cd ../
+[ if you have greenstone 2 building:
+cvs update -dP gli
+cvs checkout -P gs2build
+Note that the gs2build one uses checkout not update.
+]
+ant -Dnocvs.mode=yes update
+
Index: /greenstone3/trunk/README.txt
===================================================================
--- /greenstone3/trunk/README.txt	(revision 14125)
+++ /greenstone3/trunk/README.txt	(revision 14125)
@@ -0,0 +1,227 @@
+Greenstone 3 (GSDL3)
+Copyright (C) 2003 New Zealand Digital Libraries, University Of Waikato
+Greenstone3 comes with ABSOLUTELY NO WARRANTY; for details see LICENSE.txt
+This is free software, and you are welcome to redistribute it
+
+You will need Java and Ant to run Greenstone 3. 
+
+Your Java version should be 1.4 or higher. We recommend Sun Java. You need the SDK (development environment). Set the environment variable JAVA_HOME to be the root of your Java installation.
+
+Ant (Apache's Java based build tool) can be downloaded from http://ant.apache.org/bindownload.cgi. Set the environment variable ANT_HOME to be the root of your Ant installation, and make sure the Ant executables are on your PATH. You may have problems with earlier versions. This has been tested with version 1.6.2
+
+In the greenstone3 directory, you can run 'ant' which will give you a help message.
+Running 'ant -projecthelp' gives a list of the targets that you can run - these
+do various things like compile the source code, start up the server etc.
+
+Installing Greenstone
+---------------------------------------------------------
+
+Download the appropriate installer from sourceforge.net/projects/greenstone3 and run it. 
+
+See 'Installing from a Source Distribution' section below for extra notes about installing from Source.
+
+See the README-CVS.txt file for extra notes about installing from CVS.
+
+Running Greenstone:
+---------------------------------------------------------
+
+To start up Greenstone, select Greenstone 2 Digital Library from the Start menu (Windows), or run gs3-server.sh/bat. This launches a small server program, which starts up Tomcat and launches a browser. A small window pops up which allows you to chnage some settings for your library and restart the Tomcat server. Closing this program will stop Tomcat running.
+
+Alternatively, you can start Tomcat directly through using Ant. 'ant start', 'ant restart' and 'ant stop' starts, restarts and shuts down Tomcat, respectively. This will only start/stop a local server (one installed by Greenstone). You will need to manually start/stop an external Tomcat (see below for notes about using a version of Tomcat external to Greenstone).
+
+Once the Tomcat server is running, Greenstone will be available in a browser at "http://localhost:8080/greenstone3" (or whatever port you specified during the 
+installation process).
+You can change the port number using File->Settings in the server program, or by changing the 'tomcat.port' property in build.properties, then running 'ant configure'.
+
+Building Collections:
+----------------------------------------------------------
+
+You need to have Perl installed and on your PATH. Perl is included as part of 
+the Windows binary distribution.
+run  'ant gli", or cd to greenstone3/gli and run gli4gs3.sh/bat. This is a 
+graphical tool for building collections. Once you have created and built a 
+collection, you can see it by clicking 'Preview collection' on the Build panel.
+
+Note that GLI doesn't start up the Greenstone Tomcat server so you should 
+run 'ant start' before previewing your collection.
+
+
+Greenstone Admin
+------------------------------------------------------
+
+The Greenstone admin tool is currently under development.
+
+Using SOAP:
+-------------------------------------------------------
+
+Greenstone comes with Apache Axis installed as part of the Greenstone web application. However, no SOAP services are deployed by default.
+
+To deploy a SOAP server for localsite, run 'ant deploy-localsite'. You should now be able to see all localsite's collections through the gateway servlet. (http://localhost:8080/greenstone3/gateway)
+
+To set up a SOAP server on a new site, run
+ant soap-deploy-site
+This will prompt you for the sitename (the directory name), and the site uri - this should be a unique identifier for the site's web service. 
+
+For a non-interactive version, run
+ant -Daxis.sitename=xxx -Daxis.siteuri=yyy soap-deploy-site
+
+The service is accessible at http://localhost:8080/greenstone3/services/<siteuri>
+(or http://<computer-web-address>:<port>/greenstone3/services/<siteuri>)
+
+Note: Deploying a SOAP service for any site other than localsite requires the Greenstone source code to be installed. This is not installed by default for a binary distribution. To get the source code, re-run the installer, select custom install and deselect everything except the source code.
+
+Using External Tomcat:
+---------------------------------------------------
+
+If you want to use an existing Tomcat, set the path to its base directory
+in build.properties (tomcat.installed.path). Also set the tomcat.port property to be the port you are running Tomcat on, and change tomcat.server if the web address is not localhost. Then run 'ant configure'.
+
+ You will need to modify the Tomcat setup slightly.
+
+1. Tell Tomcat about the Greenstone web app. There are two ways to do this.
+
+A. Copy the file greenstone3/resources/tomcat/greenstone3.xml into Tomcat's conf/Catalina/localhost directory. You'll need to edit the file and replace @gsdl3webhome@ with the full path to the web directory of your greenstone 3 installation. Any path separator is fine here ('/', '\\', '\').
+
+B. Alternatively, you can move (and rename) the greenstone3/web directory to tomcat/webapps/greenstone3 (i.e. the resulting directories will be like
+tomcat/webapps/greenstone3/WEB-INF, no web directory). This should be done after running the initial 'ant install'.
+
+You will need to set the web.home property in the build.properties file
+i.e.
+web.home=${tomcat.installed.path}/webapps/greenstone3
+And then run 'ant configure' to reset gsdl3home.
+
+2. Set up the JNI libraries and Java wrappers.
+JNI libraries and their Java wrappers cannot go into the web app. The libraries need to be loaded by the same class loader as their wrappers. The libraries need to be in java.library.path, and I think get loaded by the system class loader.
+The wrappers need to be loaded by this too. 
+
+These JNI bits are located by default in the lib/jni directory. There are two ways to get them into Tomcat:
+A: Keep all the Greenstone stuff inside the greenstone3 directory, and just modify the environment that Tomcat runs in
+
+Set LD_LIBRARY_PATH (GNU/Linux), DYLD_LIBRARY_PATH (Mac OS X) or PATH/Path (windows) to include the  greenstone3/lib/jni directory.
+Add all the jar files in greenstone3/lib/jni directory to the CLASSPATH, then edit tomcats setclasspath.sh/bat to use the system CLASSPATH.
+(in setclasspath.bat, change 
+set CLASSPATH=%JAVA_HOME%\lib\tools.jar
+to 
+set CLASSPATH=%JAVA_HOME%\lib\tools.jar;%CLASSPATH%
+
+in setclasspath.sh, change
+# Set standard CLASSPATH
+if [ "$1" = "debug" -o "$1" = "javac" ] ; then
+  CLASSPATH="$JAVA_HOME"/lib/tools.jar
+fi
+
+to
+# Set standard CLASSPATH
+if [ "$1" = "debug" -o "$1" = "javac" ] ; then
+  CLASSPATH="$JAVA_HOME"/lib/tools.jar:"$CLASSPATH"
+fi
+
+
+B: Copy the files into Tomcat installation:
+Move the greenstone3/lib/jni jar files into tomcat's shared/lib directory.
+Move the greenstone3/lib/jni library files (.so for GNU/Linux, .jnilib for Mac OS X .dll for Windows) into shared/classes, and set LD_LIBARARY_PATH (GNU/Linux), DYLD_LIBRARY_PATH (Mac OS X) or PATH/Path (Windows) to include this directory.
+ This has the advantage that you can use this for other webapps without modifying the Tomcat environment.
+
+Once all these changes have been made, you will need to restart the Tomcat server for them to take effect.
+
+
+Notes for Mac OS
+------------------------------------------------
+
+Set JAVA_HOME to be /Library/Java/Home
+
+Notes for Windows
+-----------------------------------------------
+
+You can set environment variables by going to Control Panel->System->Advanced->Environment Variables. 
+
+Installing from a Source Distribution
+----------------------------------------------
+
+Download the greenstone-3.xx-src.tar.gz package from sourceforge.net/projects/greenstone3, and unpack it.
+In the greenstone3 directory, edit the build.properties file and run 
+ant prepare install
+
+Tomcat will be installed as part of the prepare process. To stop this set the tomcat.installed.path to be the root of an existing Tomcat installation. 
+
+* Solaris notes:
+** Make sure /usr/local/bin is in your PATH ahead of /usr/bin etc.
+** Add /usr/local/lib to LD_LIBARY_PATH
+** The gdbm database files (gs2mgdemo and gs2mgppdemo collections) were generated on a Mac, and don't seem to be compatible with Solaris. A text version of the file (database.txt) is included in the index/text directory. After installing Greenstone, and before running it, you'll need to:
+in greenstone3/gs2build directory: run 'source setup.bash' (Or if you have greenstone 2 already installed, run 'source setup.bash' in your greenstone 2 installation)
+in greenstone3/web/sites/localsite/collect/gs2mgdemo/index/text directories, run 'txt2db gs2mgdemo.bdb < database.txt'
+in greenstone3/web/sites/localsite/collect/gs2mgppdemo/index/text directories, run 'txt2db gs2mgppdemo.bdb < database.txt'
+** GLI shell scripts may not work like "./gli4gs3.sh". In this case, run "bash ./gli4gs3.sh" etc. You will need to compile GLI by hand (run "bash ./makegli.sh" in greenstone3/gli directory).
+** Set CC=gcc environment variable if you don't have cc, before running ant install.
+
+* Windows notes:
+** You need to have Visual Studio installed to compile the C/C++ code. Set the path to the setup file in build.properties (compile.windows.c++.setup).
+
+Configuring your installation:
+--------------------------------------------------------
+
+The file build.properties contains various parameters that can be set by the user. Please check these settings before running the install.
+Note, either forward slash '/' or double backslash '\\' can be used as path separators in the build.properties file, but not single backslash '\'. 
+
+Greenstone 3 comes with Tomcat bundled in.  
+
+If you already have Tomcat running, you can set the 'tomcat.installed.path' property (in build.properties) to the base directory of your Tomcat installation, and Greenstone will not use its own Tomcat. (You can delete the packages/tomcat directory if you like.) Please read the section "Using External Tomcat" for details about how to configure Tomcat for Greenstone.
+
+Mac OS X: You need to have GDBM installed (http://www.gnu.org/software/gdbm/gdbm.html). Please set the gdbm.installed.path property (in build.properties) to the root of your gdbm installation if it is not installed in a default place. If you run GLI or GS2 collection building from the command line, you will need to set the DYLD_LIBRARY_PATH environment variable to include <path-to-gdbm>/lib.
+
+The install target will ask you if you accept the properties before starting.
+To suppress this prompt, use the -Dproperties.accepted=yes flag. E.g.
+ant -Dproperties.accepted=yes install 
+
+To log the output in build.log, run
+ant -Dproperties.accepted=yes -logfile build.log  install 
+
+Recompiling
+-------------------------------------------------------
+To recompile your Greenstone3 installation, in the top level greenstone3 directory, run:
+
+ant configure
+ant configure-c++
+ant clean
+ant compile
+
+The compile target does Java and C/C++ compilation. On Windows, you need to set the compile.windows.c++.setup property to be your Visual Studio setup batch file. 
+
+Any sub targets can be run by themselves. Run 'ant -projecthelp' for a list of public targets, otherwise you can look at the build.xml file to see which targets depend on other ones.
+
+
+Notes on Versions of Third Party packages
+-----------------------------------------------
+
+Tomcat:
+
+apache-tomcat-5.5.12.zip: latest production quality release as of October, 2005.
+apache-tomcat-5.5.12-compat.zip: Tomcat 5 requires Java 1.5. If using Java 1.4, need to use this compatibility module.
+
+website: http://tomcat.apache.org/
+download: http://tomcat.apache.org/download-55.cgi
+
+Axis:
+
+Apache Web Services Project, SOAP implementation. Axis is a follow on project to Apache SOAP
+
+axis-bin-1_2_1.zip: latest stable release as of October, 2005
+website: http://ws.apache.org/axis/
+download: http://www.apache.org/dyn/closer.cgi/ws/axis/1_2_1
+
+All available from www.greenstone.org/gs3files if not available at their respective websites.
+
+Other Notes:
+-------------------------------------------------
+
+See greenstone3/docs/manual/manual.pdf for more details about the software and installation etc.
+
+Output is logged to web/logs. usage.log is a usage log, while greenstone.log is the error/message log. To change the level of logging, edit the web/WEB-INF/classes/log4j.properties file, and change the log4j.disable property. Valid values are TRACE, DEBUG, INFO, WARN, ERROR and FATAL.
+
+To prevent Tomcat showing directory listings, edit Tomcat's conf/web.xml file and set the value of the "listings" servlet parameter to false.
+
+To enable symlinks to files outside the webapp root directory, edit Tomcat's conf/Catalina/localhost/greenstone3.xml file, and set the allowLinking attribute in the Context element to true.
+(Note from Tomcat website: This flag MUST NOT be set to true on the Windows platform (or any other OS which does not have a case sensitive filesystem), as it will disable case sensitivity checks, allowing JSP source code disclosure, among other security problems.)
+
+The file web/WEB-INF/classes/global.properties is generated on install and contains some properties for the run time system.
+
Index: /greenstone3/trunk/bin/script/ConstructCollection
===================================================================
--- /greenstone3/trunk/bin/script/ConstructCollection	(revision 14125)
+++ /greenstone3/trunk/bin/script/ConstructCollection	(revision 14125)
@@ -0,0 +1,30 @@
+#!/bin/sh
+echo "Constructing collections ..."
+ 
+if [ "x$GSDLHOME" = "x" ] ; then
+  echo "You must have GSDLHOME set for building to work"
+  exit
+fi
+ 
+if [ "x$GSDL3HOME" = "x" ] ; then
+  echo "You must have GSDL3HOME set for building to work"
+  exit
+fi
+ 
+if [ "x$GSDLOS" = "x" ] ; then
+  echo "You must have GSDLOS set for building to work"
+  exit
+fi
+ 
+
+# -Xms32M          To set minimum memory
+# -Xmx32M          To set maximum memory
+# -verbose:gc      To set garbage collection messages
+# -Xincgc          For incremental garbage collection
+# -Xprof           Function call profiling
+# -Xloggc:<file>   Write garbage collection log
+ 
+echo "running java -DGSDLHOME=$GSDLHOME -DGSDLOS=$GSDLOS -DGSDL3HOME=$GSDL3HOME -DPATH=$PATH org.greenstone.gsdl3.build.ConstructCollection  $*"
+java -DGSDLHOME=$GSDLHOME -DGSDLOS=$GSDLOS -DGSDL3HOME=$GSDL3HOME -DPATH=$PATH org.greenstone.gsdl3.build.ConstructCollection  $*
+ 
+echo "Done!"
Index: /greenstone3/trunk/bin/script/convert_coll_from_gs2.pl
===================================================================
--- /greenstone3/trunk/bin/script/convert_coll_from_gs2.pl	(revision 14125)
+++ /greenstone3/trunk/bin/script/convert_coll_from_gs2.pl	(revision 14125)
@@ -0,0 +1,758 @@
+#!/usr/bin/perl -w
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDL3HOME not set\n" unless defined $ENV{'GSDL3HOME'};
+    die "GSDL3SRCHOME not set\n" unless defined $ENV{'GSDL3SRCHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDL3SRCHOME'}/lib/perl/cpan");
+}
+
+use colcfg;
+use util;
+use parsargv;
+use FileHandle;
+use XML::Writer;
+#can't get this to work on windows
+#use GDBM_File;
+
+use strict;
+
+&main();
+sub print_usage() {
+    print STDOUT "Usage: convert_coll_from_gs2.pl [options] coll-name\n";
+    print STDOUT "options:\n";
+    
+    print STDOUT "   -collectdir         Directory where collection lives.\n";
+    print STDOUT "   -verbosity          Controls the amount of output.\n";
+    print STDOUT "   -defaultlang        The language that is considered the default (for display text etc). defaults to 'en'\n\n";
+}
+
+
+sub main {
+
+    my ($defaultlang, $verbosity, $collectdir);
+    # note that no defaults are passed for most options as they're set
+    # later (after we check the collect.cfg file)
+    if (!&parsargv::parse(\@ARGV,
+			  'verbosity/\d+/', \$verbosity,
+			  'collectdir/.*/', \$collectdir,
+			  'defaultlang/.*/', \$defaultlang)) {
+	&print_usage();
+	die "\n";
+    }
+
+    # get and check the collection name
+    my ($collection) = @ARGV;
+    if (!defined($collection) || $collection eq "") {
+	die "No collection specified\n";
+    }
+    if ($collection eq "gs2model") {
+	die "You cant convert the model collection\n";
+    }
+    
+    if (!defined $collectdir || $collectdir eq "") {
+	$collectdir = &util::filename_cat ($ENV{'GSDLHOME'}, "collect");
+    }
+
+    if (!defined $defaultlang || $defaultlang eq "") {
+	$defaultlang = 'en';
+    }
+    # add on the coll name
+    $collectdir = &util::filename_cat ($collectdir, $collection);
+    
+    my $collconfigfilename = &util::filename_cat ($collectdir, "etc", "collect.cfg");
+    print STDOUT "coll config=$collconfigfilename\n";
+    my $collectcfg;
+    if (-e $collconfigfilename) {
+	$collectcfg = &colcfg::read_collect_cfg ($collconfigfilename);
+
+    } else {
+	print STDERR "collect.cfg not found!!";
+	die "\n";
+    }
+    
+
+    my $buildconfigfilename = &util::filename_cat ($collectdir, "index", "build.cfg");
+    my $buildcfg;
+    if (-e $buildconfigfilename) {
+	$buildcfg = &colcfg::read_build_cfg ($buildconfigfilename);
+
+    } else {
+	print STDERR "build.cfg not found!!";
+	die "\n";
+    }
+    
+
+     
+    my $colloutfile = &util::filename_cat ($collectdir, "etc", "collectionConfig.xml");
+    if (-e $colloutfile) {
+	print STDOUT "collectionConfig file already exists! overwriting it!\n";
+	
+    }
+   
+    my $buildoutfile = &util::filename_cat ($collectdir, "index", "buildConfig.xml");
+    if (-e $buildoutfile) {
+	print STDOUT "buildConfig file already exists! overwriting it!\n";
+	
+    }
+
+#    my $db_file = &util::filename_cat ($collectdir, "index", "text", "$collection.ldb");
+    my $database;
+#    if (-e $db_file) {
+#	$database = &open_database($db_file);
+#    } else {
+#	print STDERR "gdbm database file $db_file not found!!";
+#	die "\n";
+#    }
+    
+    my $buildtype;
+    if (defined $buildcfg->{'buildtype'}) {
+	$buildtype = $buildcfg->{'buildtype'};
+    } else {
+	$buildtype = 'mg';
+    }
+    
+    my $indexstem = undef;
+    if (defined $buildcfg->{'indexstem'}) {
+	$indexstem = $buildcfg->{'indexstem'};
+    }
+
+    my $buildoutput = new IO::File(">$buildoutfile");
+    my $buildwriter = new XML::Writer(OUTPUT => $buildoutput, NEWLINES => 1);
+    
+    $buildwriter->startTag('buildConfig', 'xmlns:gsf'=>"http://www.greenstone.org/greenstone3/schema/ConfigFormat");
+    
+    my $colloutput = new IO::File(">$colloutfile");
+    my $collwriter = new XML::Writer(OUTPUT => $colloutput, NEWLINES => 1);
+    
+    $collwriter->startTag('collectionConfig', 'xmlns:gsf'=>"http://www.greenstone.org/greenstone3/schema/ConfigFormat", 'xmlns:xsl'=>'http://www.w3.org/1999/XSL/Transform');
+    
+    #output the collection metadata to the collectionConfig file
+    $collwriter->startTag('metadataList');
+    
+    my $creator = $collectcfg->{'creator'};
+    &output_metadata($collwriter, 'creator', $creator);
+    my $public =$collectcfg->{'public'};
+    &output_metadata($collwriter, 'public', $public);
+    $collwriter->endTag('metadataList');
+
+    #output the display collectionmeta to collectionConfig.xml
+    
+    my $collectionmeta = $collectcfg->{'collectionmeta'};
+    if (defined $collectionmeta) {
+	my %name_map = ('collectionname', 'name',
+		     'collectionextra', 'description',
+		     'iconcollection', 'icon',
+		     'iconcollectionsmall', 'smallicon');
+	
+	$collwriter->startTag('displayItemList');
+	foreach my $entry ( keys %$collectionmeta) {
+	    if (defined $name_map{$entry}) {
+		my $name= $name_map{$entry};
+		foreach my $lang (keys %{$collectionmeta->{$entry}}) {
+		    my $value = $collectionmeta->{$entry}->{$lang};
+		    if ($entry =~ /^icon/) {
+			$value = format_icon_value($value);
+		    } else {
+			$value = tidy_up_display_item($value);
+		    }
+		    &output_display($collwriter, $name, $lang, $value);
+		}
+	    }
+	}
+	$collwriter->endTag('displayItemList');
+    } 
+    
+    # output building metadata to build config file 
+    my $numdocs = $buildcfg->{'numdocs'};
+    $buildwriter->startTag('metadataList');
+    &output_metadata($buildwriter, 'numDocs', $numdocs);
+    &output_metadata($buildwriter, 'buildType', $buildtype);
+    $buildwriter->endTag('metadataList');
+    
+    
+    #indexes
+    # maps index name to shortname
+    my $indexmap = {};
+    # keeps the order for indexes
+    my @indexlist = ();
+    my $defaultindex = "";
+    my $first = 1;
+    my $maptype = "indexfieldmap";
+    if ($buildtype eq "mg") {
+	$maptype = "indexmap";
+    }
+    if (defined $buildcfg->{$maptype}) {
+	my $indexmap_t = $buildcfg->{$maptype};
+	foreach my $i (@$indexmap_t) {
+	    my ($k, $v) = $i =~ /^(.*)\-\>(.*)$/;
+	    $indexmap->{$k} = $v;
+	    push @indexlist, $k;
+	    if ($first) {
+		$defaultindex = $v;
+		$first = 0;
+	    }	
+	}
+    } else {
+	print STDERR "$maptype not defined";
+    }
+    # we use the shortname for default index
+    if (defined $collectcfg->{'defaultindex'}) {
+	$defaultindex = $collectcfg->{'defaultindex'};
+	$defaultindex = $indexmap->{$defaultindex};
+    }
+    
+    #  levels
+    my $levelmap = {};
+    my @levellist = ();
+    my $default_search_level = "";
+    my $default_retrieve_level = "Sec";
+    $first = 1;
+    if ($buildtype eq "mgpp" || $buildtype eq "lucene") {
+	if (defined $buildcfg->{'levelmap'}) {
+	    my $levelmap_t = $buildcfg->{'levelmap'};
+	    foreach my $l (@$levelmap_t) {
+		my ($k, $v) = $l =~ /^(.*)\-\>(.*)$/;
+		$levelmap->{$k} = $v;
+		push @levellist, $k;
+		if ($first) {
+		    $default_search_level = $v;
+		    $first = 0;
+		}
+	    }
+	}
+
+	if (defined $collectcfg->{'defaultlevel'}) {
+	    $default_search_level = $collectcfg->{'defaultlevel'};
+	    $default_search_level = $levelmap->{$default_search_level};
+	}
+	if (defined $buildcfg->{'textlevel'}) {
+	    $default_retrieve_level = $buildcfg->{'textlevel'};
+	}
+    }
+    # format stuff
+    my $format = $collectcfg->{'format'};
+
+    #output the search stuff to coll cfg
+    $collwriter->startTag('search');
+    foreach my $i (keys %$indexmap) {
+	$collwriter->startTag('index', 'name'=>$i);
+	#find the coll meta stuff
+	my $indexdisplay = ".$i";
+	foreach my $lang (keys %{$collectionmeta->{$indexdisplay}}) {
+	    my $value = $collectionmeta->{$indexdisplay}->{$lang};
+	    output_display($collwriter, 'name', $lang, $value);
+	}
+	$collwriter->endTag('index');
+    }
+
+    #  level stuff for mgpp/lucene
+    if ($buildtype eq 'mgpp' || $buildtype eq 'lucene'){
+	foreach my $l (keys %$levelmap) {
+	    $collwriter->startTag('level', 'name'=>$l);
+	    #find the coll meta stuff
+	    my $leveldisplay = ".$l";
+	    foreach my $lang (keys %{$collectionmeta->{$leveldisplay}}) {
+		my $value = $collectionmeta->{$leveldisplay}->{$lang};
+		output_display($collwriter, 'name', $lang, $value);
+	    }
+	    $collwriter->endTag('level');
+	}
+    }
+    # add in the format stuff
+    if (defined $format->{'SearchVList'}) {
+	
+	$collwriter->startTag('format');
+	write_format($collwriter, $format->{'SearchVList'}, "document");
+	$collwriter->endTag('format');
+    }
+    elsif (defined $format->{'VList'}) {
+	$collwriter->startTag('format');
+	write_format($collwriter, $format->{'VList'}, "document");
+	$collwriter->endTag('format');
+    }	
+    
+    $collwriter->endTag('search');
+    
+    $buildwriter->startTag('serviceRackList');
+    
+    my @levels = ();
+    my $defaultlevel;
+    my $service_type = "MG";
+    if ($buildtype eq 'mgpp') {
+	$service_type = "MGPP";
+    } elsif ($buildtype eq "lucene") {
+	$service_type = "Lucene";
+    }
+
+    #do the retrieve service
+    $buildwriter->startTag('serviceRack', 'name'=>"GS2".$service_type."Retrieve");
+    if ($buildtype eq 'mgpp' || $buildtype eq 'lucene') {
+	$buildwriter->emptyTag('defaultLevel', 'shortname'=>$default_retrieve_level);
+    } elsif ($buildtype eq "mg") {
+	$buildwriter->emptyTag('defaultIndex', 'shortname'=>$defaultindex);
+	
+    }
+    if (defined $indexstem) {
+	$buildwriter->emptyTag('indexStem', 'name'=>$indexstem);
+    } 
+    # close off the Retrieve service
+    $buildwriter->endTag('serviceRack');
+
+    # add in the classifiers if needed
+
+    my $count = 1;
+    my $phind = 0;
+    my $started_classifiers = 0;
+    if (defined $collectcfg->{'classify'}) { 
+	$collwriter->startTag('browse');
+	# add in default format if necessary
+	if (defined $format->{"VList"} || defined $format->{"HList"}) {
+	    # global formats
+	    $collwriter->startTag('format');
+	    if (defined $format->{"VList"}) {
+		# VLIst applies to both classifier and doc nodes
+		write_format($collwriter, $format->{"VList"}, "document");
+		write_format($collwriter, $format->{"VList"}, "classifier");
+	    }
+	    if (defined $format->{"HList"}) {
+		# hlist is only for classifier nodes
+		write_format($collwriter, $format->{"HList"}, "horizontal");
+	    }
+	    $collwriter->endTag('format');
+	}
+	my $classifiers = $collectcfg->{'classify'};
+	foreach my $cl (@$classifiers) {
+	    my $name = "CL$count";
+	    $count++;
+	    my ($classname) = @$cl[0];
+	    if ($classname =~ /^phind$/i) {
+		$phind=1;
+		#should add it into coll config classifiers
+		next;
+	    }
+	    
+	    my $horizontalAtTop = &isHorizontalClassifier($database, $name);
+	    if (not $started_classifiers) {
+		$buildwriter->startTag('serviceRack', 'name'=>'GS2Browse');
+		if (defined $indexstem) {
+		    $buildwriter->emptyTag('indexStem', 'name'=>$indexstem);
+		} 
+
+		$buildwriter->startTag('classifierList');		
+		$started_classifiers = 1;
+	    }
+	    my $content = ''; #use buttonname first, then metadata
+	    if ($classname eq "DateList") {
+		$content = "Date";
+	    } else {
+		for (my $i=0; $i<scalar(@$cl); $i++) {
+		    my $arg = @$cl[$i];
+		    if ($arg eq "-buttonname"){
+			$content = @$cl[$i+1];
+			last;
+		    } elsif ($arg eq "-metadata") {
+			$content = @$cl[$i+1];
+		    }
+		    
+		}
+	    }
+	    if ($horizontalAtTop) {
+		$buildwriter->emptyTag('classifier', 'name'=>$name, 'content'=>$content, 'horizontalAtTop'=>'true');
+	    } else {
+		$buildwriter->emptyTag('classifier', 'name'=>$name, 'content'=>$content);
+	    } 
+	    
+	    
+	    $collwriter->startTag('classifier', 'name'=>$name);
+	    my $vlist = $name."VList";
+	    my $hlist = $name."HList";
+	    my $dlist = "";
+	    if ($classname eq "DateList") {
+		$dlist = "DateList";
+	    }
+	    # need to work out how to split into classifier and document
+	    if (defined $format->{$vlist} || defined $format->{$hlist} || defined $format->{$dlist}) {
+		$collwriter->startTag('format');
+		if (defined $format->{$vlist}) {
+		    write_format($collwriter, $format->{$vlist}, "document");
+		    write_format($collwriter, $format->{$vlist}, "classifier");
+		} 
+		if (defined $format->{$hlist}) {
+		    write_format($collwriter, $format->{$hlist}, "horizontal");
+		} 
+		
+		if (defined $format->{$dlist}) {
+		    write_format($collwriter, $format->{$dlist}, "document");
+		}
+		$collwriter->endTag('format');
+	    }
+	    $collwriter->endTag('classifier');
+	} #foreach classifier
+	if ($started_classifiers) {
+	    # end the classifiers
+	    $buildwriter->endTag('classifierList');
+	    # close off the Browse service
+	    $buildwriter->endTag('serviceRack');
+	}
+	
+	$collwriter->endTag('browse');
+    }
+    
+    
+    # the phind classifier is a separate service
+    if ($phind) {
+	# if phind classifier
+	$buildwriter->emptyTag('serviceRack', 'name'=>'PhindPhraseBrowse');
+    }
+   
+    # do the search service
+    $buildwriter->startTag('serviceRack', 'name'=>'GS2'.$service_type.'Search');
+    $buildwriter->emptyTag('defaultIndex', 'shortname'=>$defaultindex);
+    $buildwriter->startTag('indexList');
+    #for each index
+    foreach my $i (@indexlist) {
+	my $index = $indexmap->{$i};
+	$buildwriter->emptyTag('index', 'name'=>$i, 'shortname'=>$index);
+    }	
+    $buildwriter->endTag('indexList');
+    if (defined $indexstem) {
+	$buildwriter->emptyTag('indexStem', 'name'=>$indexstem);
+    } 
+    
+    # index options
+    if ($buildtype eq 'mg' || $buildtype eq 'mgpp') {
+	$buildwriter->startTag('indexOptionList');
+	my $stemindexes = 3; # default is stem and casefold
+	if (defined $buildcfg->{'stemindexes'} && $buildcfg->{'stemindexes'} =~ /^\d+$/ ) {
+	    $stemindexes = $buildcfg->{'stemindexes'};
+	}
+	$buildwriter->emptyTag('indexOption', 'name'=>'stemIndexes', 'value'=>$stemindexes);
+	
+	my $maxnumeric = 4; # default
+	if (defined $buildcfg->{'maxnumeric'} && $buildcfg->{'maxnumeric'} =~ /^\d+$/) {
+	    $maxnumeric = $buildcfg->{'maxnumeric'};
+	}
+	$buildwriter->emptyTag('indexOption', 'name'=>'maxnumeric', 'value'=>$maxnumeric);
+	
+	$buildwriter->endTag('indexOptionList');
+    }
+
+    if ($buildtype eq 'mgpp' || $buildtype eq 'lucene') {
+		
+	# level info
+	$buildwriter->emptyTag('defaultLevel', 'shortname'=>$default_search_level);
+	$buildwriter->emptyTag('defaultGDBMLevel', 'shortname'=>$default_retrieve_level);
+	$buildwriter->startTag('levelList');
+	foreach my $l (@levellist) {
+	    my $level = $levelmap->{$l};
+	    $buildwriter->emptyTag('level', 'name'=>$l, 'shortname'=>$level);
+	}	
+	$buildwriter->endTag('levelList');
+	
+	# do the search types if there
+	if (defined $collectcfg->{'searchtype'}) {
+	    $buildwriter->startTag('searchTypeList');
+	    foreach my $st (@{$collectcfg->{'searchtype'}}) {
+		$buildwriter->emptyTag('searchType', 'name'=>$st);
+	    }
+	    $buildwriter->endTag('searchTypeList');
+	} elsif (defined $format->{'SearchTypes'}) {
+	    #check format statement 
+	    my $searchtype = $format->{'SearchTypes'};
+	    $buildwriter->startTag('searchTypeList');
+	    if ($searchtype =~ /form/) {
+		$buildwriter->emptyTag('searchType', 'name'=>'form');
+	    }
+	    if ($searchtype =~ /plain/) {
+		$buildwriter->emptyTag('searchType', 'name'=>'plain');
+	    }
+	    $buildwriter->endTag('searchTypeList');
+	}
+    } 
+    
+
+    
+    $buildwriter->endTag('serviceRack');
+    
+    $buildwriter->endTag('serviceRackList');
+    $buildwriter->endTag('buildConfig');
+
+    # we add in the default replace list just in case we have macros in the 
+    # collection
+    $collwriter->emptyTag('replaceListRef', 'id'=>'gs2-standard');
+    $collwriter->endTag('collectionConfig');
+    $collwriter->end();
+    $buildwriter->end();
+    $buildoutput->close();
+    $colloutput->close();
+    &close_database($database);
+}
+
+
+sub output_metadata {
+    my ($writer, $metaname,  $metavalue) = @_;
+    $writer->startTag('metadata',  'name'=>$metaname);
+    $writer->characters($metavalue);
+    $writer->endTag('metadata');
+}
+
+sub output_display {
+    my ($writer, $name, $lang, $value) = @_;
+    $lang = 'en' if $lang eq 'default';
+    if ($lang =~ /^\[/) {
+	($lang) = $lang =~ /\[l=(.*)\]/;
+    }
+    $writer->startTag('displayItem', 'name'=>$name, 'lang'=>$lang);
+    $writer->characters($value);
+    $writer->endTag('displayItem');
+}
+sub format_icon_value {
+    my ($value) = @_;
+    if ($value =~ /^_/) {
+	my ($newvalue) = $value =~ /images\/(.*)$/;
+	if ($newvalue) {
+	    return $newvalue;
+	}
+    }
+    return $value;
+}
+
+sub tidy_up_display_item {
+    my ($value) = @_;
+    # remove \n
+    $value =~ s/\\n//g;
+    # replace \' with '
+    $value =~ s/\\\'/\'/g;
+    # replace \" with "
+    $value =~ s/\\\"/\"/g;
+    # replace _httpprefix_ with _httpsite_
+    $value =~ s/_httpprefix_/_httpsite_/g;
+    $value =~ s/_gwcgi_//g;
+    $value =~ s/[a-z][a-z]?=_cgiarg[a-z][a-z]?_&?//g;
+    $value =~ s/&p=/&sa=/g;
+    return $value;
+}
+
+sub write_format {
+    my ($writer, $old_format, $node_type) = @_;
+    # replace \' with '
+    $old_format =~ s/\\\'/\'/g;
+    # replace \" with "
+    $old_format =~ s/\\\"/\"/g;
+    #convert [] to <gsf:...>
+    # assume no nesting {If} or {Or} for now
+    $old_format =~ s/\{If\}\{([^\}]*)\}/&format_if($1, $node_type)/eg;
+    $old_format =~ s/\{Or\}\{([^\}]*)\}/&format_or($1)/eg;
+    $old_format =~ s/\[Text\]/\<gsf:text\/\>/g;
+    $old_format =~ s/\[num\]/\<gsf:num\/\>/g;
+    $old_format =~ s/\[link\]/\<gsf:link type=\'$node_type\'\>/g;
+    $old_format =~ s/\[\/link\]/\<\/gsf:link\>/g;
+    $old_format =~ s/\[srclink\]/\<gsf:link type=\'source\'\>/g;
+    $old_format =~ s/\[\/srclink\]/\<\/gsf:link\>/g;
+    $old_format =~ s/\[icon\]/\<gsf:icon type=\'$node_type\'\/\>/g;
+    $old_format =~ s/\[srcicon\]/\<gsf:icon type=\'source\'\/\>/g;
+		  
+    # what to do with hightlight??
+    $old_format =~ s/\[\/?highlight\]//g;
+
+    #now do the rest of the [] which are assumed to be metadata
+    $old_format =~ s/\[([^\]]*)\]/&format_metadata($1)/eg;
+  
+    # some html tidy
+    #turn <br> into <br />
+    $old_format =~ s/\<br\>/\<br \/\>/g;
+    #turn <p> into <p />
+    $old_format =~ s/\<p\>/\<p \/\>/g;
+    
+    #put quotes around any atts
+    $old_format =~ s/=([a-z]+)([> ])/=\'$1\'$2/g;
+
+    if ($node_type eq "document") {
+	$writer->startTag('gsf:template', 'match'=>'documentNode');
+	$writer->charactersXML($old_format);
+	$writer->endTag('gsf:template');
+    } elsif ($node_type eq "classifier") {
+	$writer->startTag('gsf:template', 'match'=>'classifierNode');
+	$writer->charactersXML($old_format);
+	$writer->endTag('gsf:template');
+    } elsif ($node_type eq "horizontal") {	
+	$writer->startTag('gsf:template', 'match'=>'classifierNode', 'mode'=>'horizontal');
+	$writer->charactersXML($old_format);
+	$writer->endTag('gsf:template');
+
+    }
+}
+
+sub format_metadata {
+    my ($metadata_string) = @_;
+
+    #print STDERR "original meta = $metadata_string\n"; 
+    
+    # what shall we do with cgisafe??
+    my $cgisafe = $metadata_string =~ s/^cgisafe://;
+
+    my ($select) = $metadata_string =~ /^(parent|sibling)/;
+    $metadata_string =~ s/^(parent|sibling)//;
+    my ($scope, $delim);
+    
+    if ($select) {
+	($scope) = $metadata_string =~ /^\((Top|All)/;
+	$metadata_string =~ s/^\((Top|All)\)?//;
+	if ($scope) {
+	    ($delim) = $metadata_string =~ /^\'([^\']*)\'\)/;
+	    $metadata_string =~ s/^\'([^\']*)\'\)//;
+	} 
+    }
+    $metadata_string =~ s/^://;
+    # remove ex.
+    $metadata_string =~ s/^ex\.//;
+    
+    #print STDERR "select=$select, scope=$scope, delim=|$delim|, meta = $metadata_string\n";
+    
+    my $new_format = "<gsf:metadata name='$metadata_string' ";
+    if (defined $select) {
+	if ($select eq "sibling") {
+	    $new_format .= "multiple='true' ";
+	    if (defined $delim) {
+		$new_format .= "separator='$delim' ";
+	    }
+	} elsif ($select eq "parent"){
+	    if (defined $scope) {
+		if ($scope eq "Top") {
+		    $new_format .= "select='root' ";
+		} elsif ($scope eq "All") {
+		    $new_format .= "select='ancestors' ";
+		    if (defined $delim) {
+			$new_format .= "separator='$delim' ";
+		    }
+		}
+	    } else {
+		$new_format .= "select='parent' ";
+	    }	
+	}
+    }
+    $new_format .= "/>";
+    #print STDERR "$new_format\n";
+    return $new_format;
+    
+}
+
+sub format_if {
+
+    my ($if_string, $node_type) = @_;
+    #print STDERR "if string = $if_string\n";
+
+    my @parts = split /,/, $if_string; 
+    my $test = $parts[0];
+    my $true_option = $parts[1];
+    my $false_option;
+    if (scalar (@parts) == 3) {
+	$false_option = $parts[2];
+    }
+    $test =~ s/^\s*//;
+    $test =~ s/\s*$//;
+    my ($test_meta, $test_type, $test_value);
+    if ($test =~ /^(\[.+\])$/) {
+	$test_meta = $1;
+	$test_type = 'exists';
+    } else {
+	my ($lhs, $exp, $rhs) = $test =~ /^(.+)\s+(eq|ne|lt|gt|le|ge|sw|ew)\s+(.+)$/;
+	#print STDERR "lhs, exp, rhs = $lhs, $exp, $rhs\n";
+	if ($exp eq "eq") {
+	    $test_type = "equals";
+	} elsif ($exp eq "sw") {
+	    $test_type = "startsWith";
+	} elsif ($exp eq "ew") {
+	    $test_type = "endsWith";
+	} elsif ($exp eq "ne") {
+	    $test_type = "notEquals";
+	} elsif ($exp eq "lt") {
+	    $test_type = "lessThan";
+	}elsif ($exp eq "gt") {
+	    $test_type = "greaterThan";
+	}elsif ($exp eq "le") {
+	    $test_type = "lessThanOrEquals";
+	}elsif ($exp eq "ge") {
+	    $test_type = "greaterThanOrEquals";
+	}
+	if ($lhs =~ /^\[.+\]$/) {
+	    $test_meta = $lhs;
+	    $test_value = $rhs;
+	} else {
+	    # assume rhs has meta
+	    $test_meta = $rhs;
+	    $test_value = $lhs;
+	}
+	
+	#remove beginning and end quotes
+	$test_value =~ s/^[\'\"]//;
+	$test_value =~ s/[\'\"]$//;
+    }
+    my $test_atts = "test='$test_type' ";
+    if (defined $test_value) {
+	$test_atts .= "test-value='$test_value' ";
+    }
+    #print STDERR "test, true, false = $test, $true_option, $false_option\n";
+    my $new_format = "<gsf:switch>$test_meta";
+    $new_format .= "<gsf:when $test_atts>$true_option</gsf:when>";
+    if (defined $false_option) {
+	$new_format .="<gsf:otherwise>$false_option</gsf:otherwise>";
+    }
+    $new_format .= "</gsf:switch>";
+	
+    #print STDERR "new format = $new_format\n";
+    return $new_format;
+}
+
+sub format_or {
+    my ($or_string) = @_;
+    my @meta_list = split (',', $or_string);
+    return "" unless scalar (@meta_list);
+    my $new_format = "<gsf:choose-metadata>";
+    foreach my $m (@meta_list) {
+	if ($m =~ /^\[(.*)\]$/) {
+	    $new_format .= &format_metadata($1);
+	} else {
+	    # a default value
+	    $new_format .= "<gsf:default>$m</gsf:default>";
+	    last;
+	}
+    }
+    $new_format .= "</gsf:choose-metadata>";
+    return $new_format;
+}
+
+sub open_database {
+    my ($db_file) = @_;
+    
+    my $database = ();
+#    tie (%$database, 'GDBM_File', $db_file, GDBM_READER, 0400) ||
+#	die "Couldn't open database $db_file\n";
+
+    return $database;
+}
+
+sub close_database {
+    my ($database) = @_;
+    untie %$database;
+}
+sub isHorizontalClassifier {
+    my ($database, $name) = @_;
+
+    return 0; # can't get this to work for windows
+    my $record = $database->{$name};
+    my ($childtype) = $record =~ /<childtype>(\w*)/;
+    if ($childtype eq "HList") {
+	return 1;
+    }
+    return 0;
+}
+#$writer->startTag('');
+#$writer->endTag('');
+#$writer->characters();
+#$writer->emptyTag('');
+
+1;
Index: /greenstone3/trunk/bin/script/gs2_mkcol.pl
===================================================================
--- /greenstone3/trunk/bin/script/gs2_mkcol.pl	(revision 14125)
+++ /greenstone3/trunk/bin/script/gs2_mkcol.pl	(revision 14125)
@@ -0,0 +1,297 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# gs2_mkcol.pl -- create the framework for a gs2 compatible collection in 
+# gs3
+# 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.
+
+package gs2_mkcol;
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use parsargv;
+use util;
+use cfgread;
+
+sub print_usage {
+    print STDOUT "\n";
+    print STDOUT "gs2_mkcol.pl: Creates the directory structure for a new\n";
+    print STDOUT "          Greenstone2 compatible collection in Greenstone3.\n\n";
+    print STDOUT "  usage: $0 -site site-home -creator email [options] collection-name\n\n";
+    print STDOUT "  options:\n";
+    print STDOUT "   -optionfile file    Get options from file, useful on systems where\n";
+    print STDOUT "                       long command lines may cause problems\n";
+    print STDOUT "   -collectdir         Directory where new collection will be created.\n";
+    print STDOUT "                       Default is " . 
+	&util::filename_cat("site-home", "collect") . "\n";
+    print STDOUT "   -maintainer email   The collection maintainer's email address (if\n";
+    print STDOUT "                       different from the creator)\n";
+    print STDOUT "   -public true|false  If this collection has anonymous access\n";
+    print STDOUT "   -buildtype mg|mgpp  Whether to use mg or mgpp to build the collection\n";
+    print STDOUT "                       Default is mgpp.\n";
+    print STDOUT "   -title text         The title for the collection\n";
+    print STDOUT "   -about text         The about text for the collection\n";
+    print STDOUT "   -plugin text        perl plugin module to use (there may be multiple\n";
+    print STDOUT "                       plugin entries)\n";
+    print STDOUT "   -quiet              Operate quietly\n";
+    print STDOUT "  Note that -creator and -site must be specified. You can make changes to all\n";
+    print STDOUT "  options later by editing the collect.cfg configuration file for your\n";
+    print STDOUT "  new collection (it'll be in the \"etc\" directory).\n\n";
+    print STDOUT "  [Type \"perl -S mkcol.pl | more\" if this help text scrolled off your screen]";
+    print STDOUT "\n" unless $ENV{'GSDLOS'} =~ /^windows$/i;
+}
+
+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)
+    {
+	my $thisfile = &util::filename_cat ($modeldir, $file);
+	if (-d $thisfile) {
+	    my $colfiledir = &util::filename_cat ($coldir, $file);
+	    traverse_dir ($thisfile, $colfiledir);
+
+	} else {
+	    my $destfile = $file;
+	    $destfile =~ s/^modelcol/$collection/;
+	    $destfile =~ s/^MODELCOL/$capcollection/;
+	    print STDOUT "  doing replacements for $destfile\n" unless $quiet;
+	    $destfile = &util::filename_cat ($coldir, $destfile);
+	    
+	    open (INFILE, $thisfile) || 
+		die "ERROR: Can't read file $thisfile";
+	    open (OUTFILE, ">$destfile") ||
+		die "ERROR: Can't create file $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/\*\*title\*\*/$title/g;
+		$line =~ s/\*\*about\*\*/$about/g;
+		$line =~ s/\*\*plugins\*\*/$pluginstring/g;
+		$line =~ s/\*\*buildtype\*\*/$buildtype/g;
+		$line =~ s/\*\*searchtype\*\*/$searchtype/g;
+		$line =~ s/\*\*indexes\*\*/$indexes/g;
+		$line =~ s/\*\*defaultindex\*\*/$defaultindex/g;
+		$line =~ s/\*\*indexmeta\*\*/$indexmeta/g;
+		$line =~ s/\*\*xmlindexes\*\*/$xmlindexes/g;
+		#$line =~ s/\*\*xmlplugins\*\*/$xmlpluginstring/g;
+		
+		print OUTFILE $line;
+	    }
+	    
+	    close (OUTFILE);
+	    close (INFILE);
+	}
+    }
+}
+
+# get and check options
+sub parse_args {
+    my ($argref) = @_;
+    if (!&parsargv::parse($argref,
+			  'optionfile/.*/', \$optionfile,
+			  'collectdir/.*/', \$collectdir,
+			  'site/.*/', \$sitehome,
+			  'creator/\w+\@[\w\.]+/', \$creator,
+			  'maintainer/\w+\@[\w\.]+/', \$maintainer,
+			  'public/true|false/true', \$public,
+			  'buildtype/mg|mgpp/mgpp', \$buildtype,
+			  'title/.+/', \$title,
+			  'about/.+/', \$about,
+			  'plugin/.+', \@plugin,
+			  'quiet', \$quiet,
+			  )) {
+	&print_usage();
+	die "\n";
+    }
+}
+
+sub main {
+
+    &parse_args (\@ARGV);
+    if ($optionfile =~ /\w/) {
+	open (OPTIONS, $optionfile) || die "Couldn't open $optionfile\n";
+	my $line = [];
+	my $options = [];
+	while (defined ($line = &cfgread::read_cfg_line ('mkcol::OPTIONS'))) {
+	    push (@$options, @$line);
+	}
+	close OPTIONS;
+	&parse_args ($options);
+
+    }
+
+    # load default plugins if none were on command line    
+    if (!scalar(@plugin)) {
+	@plugin = (ZIPPlug,GAPlug,TEXTPlug,HTMLPlug,EMAILPlug,
+		   PDFPlug,RTFPlug,WordPlug,PSPlug,ArcPlug,RecPlug);
+    }
+
+    # get and check the collection name
+    ($collection) = @ARGV;
+    if (!defined($collection)) {
+	print STDOUT "ERROR: no collection name was specified\n";
+	&print_usage();
+	die "\n";
+    }
+
+    if (length($collection) > 8) {
+	print STDOUT "ERROR: The collection name must be less than 8 characters\n";
+	print STDOUT "       so compatibility with earlier filesystems can be\n";
+	print STDOUT "       maintained.\n";
+	die "\n";
+    }
+
+    if ($collection eq "gs2model" || $collection eq "gs3model") {
+	print STDOUT "ERROR: No collection can be named gs2model or gs3model as these are  the\n";
+	print STDOUT "       names of the model collections.\n";
+	die "\n";
+    }
+
+    if ($collection eq "CVS") {
+	print STDOUT "ERROR: No collection can be named CVS as this may interfere\n";
+	print STDOUT "       with directories created by the CVS versioning system\n";
+	die "\n";
+    }
+
+    #check that -site has been specified
+    if (!defined($sitehome) || $sitehome eq "") {
+	print STDOUT "ERROR: The site was not defined. This variable is\n";
+	print STDOUT "       needed to locate the collect directory.\n";
+	die "\n";
+    }
+    #check that its a valid directory
+    if (!-d $sitehome) {
+	print STDOUT "ERROR: $sitehome doesn't exist\n";
+	die "\n";
+    }
+    if (!defined($creator) || $creator eq "") {
+	print STDOUT "ERROR: The creator was not defined. This variable is\n";
+	print STDOUT "       needed to recognise duplicate collection names.\n";
+	die "\n";
+    }
+
+    if (!defined($maintainer) || $maintainer eq "") {
+	$maintainer = $creator;
+    }
+
+    $public = "true" unless defined $public;
+    $buildtype = "mgpp" unless defined $buildtype;
+
+    $searchtype = "";
+    if ($buildtype eq "mgpp") {
+	$searchtype = "searchtype  plain form";
+    }
+    
+    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.
+    $pluginstring = "";
+    foreach $plugin (@plugin) {
+	if ($plugin eq RecPlug) {
+	    $pluginstring .= "plugin         $plugin -use_metadata_files\n";
+	} else {
+	    $pluginstring .= "plugin         $plugin\n";
+	}
+    }
+
+    $mdir = &util::filename_cat ($sitehome, "collect", "gs2model");
+    
+    if (defined $collectdir && $collectdir =~ /\w/) {
+	if (!-d $collectdir) {
+	    print STDOUT "ERROR: $collectdir doesn't exist\n";
+	    die "\n";
+	}
+	$cdir = &util::filename_cat ($collectdir, $collection);
+    } else {
+	$cdir = &util::filename_cat ($sitehome, "collect", $collection);
+    }
+
+    # make sure the model collection exists
+    die "ERROR: Cannot find the model collection $mdir" unless (-d $mdir);
+
+    # make sure this collection does not already exist
+    if (-e $cdir) {
+	print STDOUT "ERROR: This collection already exists\n";
+	die "\n";
+    }
+
+    # set up the default indexes - this could be a command line option at some stage
+    # the names are added in here for the xml ones, but they should be added after building once the names are known.
+    if ($buildtype eq "mg") {
+	$indexes = "document:text document:Title document:Source";
+	$defaultindex = "defaultindex document:text";
+	$indexmeta = "collectionmeta .document:text    \"text\"\ncollectionmeta .document:Title  \"titles\"\ncollectionmeta .document:Source  \"filenames\"\n";
+    } elsif ($buildtype eq "mgpp") {
+	$indexes = "allfields text metadata";
+	$defaultindex = "";
+	$indexmeta = "collectionmeta .text    \"text\"\ncollectionmeta .allfields \"entire documents\"\n";
+    } else {
+	print STDOUT "Error: buildtype should be mg or mgpp, but its $buildtype\n";
+    }
+    # start creating the collection
+    print STDOUT "\nCreating the collection $collection...\n" unless $quiet;
+    &traverse_dir ($mdir, $cdir);
+    print STDOUT "\nThe new collection was created successfully at\n" unless $quiet;
+    print STDOUT "$cdir\n" unless $quiet;
+}
+
+&main ();
Index: /greenstone3/trunk/bin/script/gs3-build.bat
===================================================================
--- /greenstone3/trunk/bin/script/gs3-build.bat	(revision 14125)
+++ /greenstone3/trunk/bin/script/gs3-build.bat	(revision 14125)
@@ -0,0 +1,23 @@
+@echo off
+
+:: ---- Check that %GSDL3HOME% is set ----
+if not "%GSDL3HOME%" == "" goto start
+    echo "You need to run 'gs3-setup' in the greenstone3 directory before running this script"
+    goto exit
+
+:start
+
+if not "%1" == "" goto start2
+    echo Usage: gs3-build sitename collname
+    goto exit
+
+:start2
+if not "%2" == "" goto run
+    echo Usage: gs3-build sitename collname
+    goto exit
+
+:run
+
+java -cp "%CLASSPATH%" -DGSDL3HOME="%GSDL3HOME%"  -DGSDL3SRCHOME="%GSDL3SRCHOME%" -Dorg.xml.sax.driver=org.apache.xerces.parsers.SAXParser  org.greenstone.gsdl3.gs3build.Build -site %1 -collect %2
+
+:exit
Index: /greenstone3/trunk/bin/script/gs3-build.sh
===================================================================
--- /greenstone3/trunk/bin/script/gs3-build.sh	(revision 14125)
+++ /greenstone3/trunk/bin/script/gs3-build.sh	(revision 14125)
@@ -0,0 +1,20 @@
+#!/bin/sh 
+
+#check that GSDL3HOME is set
+if test -z "$GSDL3HOME" ; then
+  echo "You need to 'source gs3-setup.sh' in the greenstone3 directory before running this script"
+ exit;
+fi
+
+if test $# != 2; then
+  echo "Usage: gs3-build.sh <site name> <collection name>"
+  exit;
+fi
+
+sitename=$1
+collectionname=$2
+
+# we need to stop here if the database isn't running - how can we tell??
+java -DGSDL3HOME=$GSDL3HOME -DGSDL3SRCHOME=$GSDL3SRCHOME -Dorg.xml.sax.driver=org.apache.xerces.parsers.SAXParser org.greenstone.gsdl3.gs3build.Build -site $sitename -collect $collectionname
+
+
Index: /greenstone3/trunk/bin/script/gs3-mkcol.bat
===================================================================
--- /greenstone3/trunk/bin/script/gs3-mkcol.bat	(revision 14125)
+++ /greenstone3/trunk/bin/script/gs3-mkcol.bat	(revision 14125)
@@ -0,0 +1,23 @@
+@echo off
+
+:: ---- Check that %GSDL3HOME% is set ----
+if not "%GSDL3HOME%" == "" goto start
+    echo "You need to run 'gs3-setup' in the greenstone3 directory before running this script"
+    goto exit
+
+:start
+
+if not "%1" == "" goto start2
+    echo Usage: gs3-mkcol sitename collname
+    goto exit
+
+:start2
+if not "%2" == "" goto run
+    echo Usage: gs3-mkcol sitename collname
+    goto exit
+
+:run
+
+java -cp "%CLASSPATH%" -DGSDL3HOME="%GSDL3HOME%" -DGSDL3SRCHOME="%GSDL3SRCHOME%" -Dorg.xml.sax.driver=org.apache.xerces.parsers.SAXParser  org.greenstone.gsdl3.gs3build.Create -site %1 -collect %2
+
+:exit
Index: /greenstone3/trunk/bin/script/gs3-mkcol.sh
===================================================================
--- /greenstone3/trunk/bin/script/gs3-mkcol.sh	(revision 14125)
+++ /greenstone3/trunk/bin/script/gs3-mkcol.sh	(revision 14125)
@@ -0,0 +1,23 @@
+#!/bin/sh 
+
+#check that GSDL3HOME is set
+if test -z "$GSDL3HOME" ; then
+  echo "You need to 'source gs3-setup.sh' in the greenstone3 directory before running this script"
+ exit;
+fi
+
+if test $# != 2; then
+  echo "Usage: gs3-mkcol.sh <site name> <collection name>"
+  exit;
+fi
+
+sitename=$1
+collectionname=$2
+
+java -DGSDL3HOME=$GSDL3HOME -DGSDL3SRCHOME=$GSDL3SRCHOME -Dorg.xml.sax.driver=org.apache.xerces.parsers.SAXParser org.greenstone.gsdl3.gs3build.Create -site $sitename -collect $collectionname
+
+#/opt/sun-jdk-1.4.2.03/bin/java -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y -DGSDL3HOME=$GSDL3HOME -Dorg.xml.sax.driver=org.apache.xerces.parsers.SAXParser org.greenstone.gsdl3.gs3build.Build -site $sitename -collect $collectionname
+
+
+
+
Index: /greenstone3/trunk/build.properties
===================================================================
--- /greenstone3/trunk/build.properties	(revision 14125)
+++ /greenstone3/trunk/build.properties	(revision 14125)
@@ -0,0 +1,52 @@
+#### properties file for Greenstone3 building using ANT. See the README for more 
+#### information
+
+## java compilation properties - for javac
+#Should compilation include the debug option?
+compile.debug=true
+#Should compilation include the deprecation option?
+compile.deprecation=true
+#Should compilation include the optimize option?
+compile.optimize=true
+
+## windows c++ compilation
+compile.windows.c++.setup=C:/Program Files/Microsoft Visual Studio/VC98/Bin/VCVARS32.BAT
+
+## Tomcat installation
+#Set this to the internet/intranet name of the machine that Tomcat is/will be run on. localhost is fine for accessing the server from the local machine, but not remotely
+tomcat.server=localhost
+# The port number that tomcat is/will be run on
+tomcat.port=8080
+# Tomcat's shutdown port - this may need to be changed if you are running two or more Tomcats
+tomcat.shutdown.port=8005
+# If tomcat is already running, enter the path to the base directory here
+tomcat.installed.path=
+#uncomment the following if you have moved the greenstone3 web directory to tomcats webapps dir 
+#web.home=${tomcat.installed.path}/webapps/greenstone3
+
+## Collection building options
+# uncomment if you don't want to have collection building enabled
+#disable.collection.building=true
+
+## Greenstone 3 server program options
+# does running the server automatically start up Tomcat and a browser
+server.auto.start=false
+# default servlet to start with
+server.default.servlet=/library
+
+##Browser setup
+browser.path=
+
+## Proxy setup - Greenstone installation will attempt to download extra packages. Set the proxy information here if you are behind a firewall.
+# The proxy server name 
+proxy.host=
+# The proxy server port
+proxy.port=
+# A user name to use when talking to the proxy server (optional, will prompt if not entered here)
+proxy.user=
+# A password to use when talking to the proxy server (optional, will prompt if not entered here)
+proxy.password=
+
+## Mac OS X specific stuff
+# set the path to your GDBM here
+gdbm.installed.path=
Index: /greenstone3/trunk/build.xml
===================================================================
--- /greenstone3/trunk/build.xml	(revision 14125)
+++ /greenstone3/trunk/build.xml	(revision 14125)
@@ -0,0 +1,1248 @@
+<?xml version="1.0"?>
+
+<!-- ====================================================================== 
+     March 2005                                                    
+
+     Greenstone3 build and install script
+                   
+     kjdon                                                                
+     ====================================================================== -->
+<project name="greenstone3" default="usage" basedir=".">
+
+ <!-- ============ self defined tasks =================== -->
+
+  <taskdef name="mysetproxy" classname="org.greenstone.anttasks.MySetProxy" classpath="${basedir}/lib/java/anttasks.jar"/>
+  <taskdef name="getuserandpassword" classname="org.greenstone.anttasks.MyGetUserAndPassword" classpath="${basedir}/lib/java/anttasks.jar"/>
+
+
+
+<!-- ===================== Property Definitions =========================== -->
+
+<!--
+
+  Each of the following properties are used in the build script.
+  Values for these properties are set by the first place they are
+  defined, from the following list:
+
+  * Definitions on the "ant" command line (ant -Dfoo=bar compile).
+
+  * Definitions from a "build.properties" file in the top level
+    source directory of this application.
+
+  * Definitions from a "build.properties" file in the user's
+    home directory.
+
+  * Default definitions in this build.xml file.
+
+  You will note below that property values can be composed based on the
+  contents of previously defined properties.  This is a powerful technique
+  that helps you minimize the number of changes required when your development
+  environment is modified.  Note that property composition is allowed within
+  "build.properties" files as well as in the "build.xml" script.
+
+-->
+
+  <property file="build.properties"/>
+  <property file="${user.home}/build.properties"/>
+
+  <!-- get properties from the environment -->
+  <property environment="env"/>
+  <property name="build.home" value="${basedir}/build"/>
+  <property name="src.home" value="${basedir}/src/java"/>
+  <property name="src.packages.home" value="${basedir}/src/packages"/>
+  <property name="packages.home" value="${basedir}/packages"/>
+  <!-- this may be set in build.properties, eg if you move the web dir to 
+  tomcats webapps directory -->
+  <property name="web.home" value="${basedir}/web"/>
+  <!-- jar files needed by applets go here -->
+  <property name="web.applet" value="${web.home}/applet"/>
+  <!-- jar files needed by the servlet (and extra ones) go here -->
+  <property name="web.lib" value="${web.home}/WEB-INF/lib"/>
+  <!-- other files needed by the servlet go here -->
+  <property name="web.classes" value="${web.home}/WEB-INF/classes"/>
+  <!-- jni libraries and java wrappers go here -->
+  <property name="lib.jni" value="${basedir}/lib/jni"/>
+    
+  <property name="javadocs" value="${basedir}/docs/javadoc"/>
+
+  <property name="app.name"      value="greenstone3"/>
+  <property name="app.path"      value="/${app.name}"/>
+  <property name="app.version"   value="3.02"/>
+
+  <property name="cvs.root" value=":pserver:cvs_anon@cvs.scms.waikato.ac.nz:2402/usr/local/global-cvs/gsdl-src"/>
+  <!-- catalina home is set to tomcat basedir is already installed, otherwise
+  use greenstone's tomcat -->
+  <condition property="catalina.home" value="${tomcat.installed.path}"> 
+    <and>
+      <isset property="tomcat.installed.path"/>
+      <not>
+	<equals arg1="" arg2="${tomcat.installed.path}"/>
+      </not>
+    </and>
+  </condition>
+  <property name="catalina.home" value="${packages.home}/tomcat"/>
+
+  <property name="os.linux" value="Linux"/> 
+  <property name="os.mac" value="Mac OS X"/>
+  <property name="os.solaris" value="SunOS"/>
+  <property name="os.unix" value="${os.linux},${os.mac},${os.solaris}"/>
+  <property name="os.windows" value="Windows 95,Windows 98,Windows 2000,Windows XP,Windows NT,Windows ME"/> <!-- check this!!!-->
+
+  <!-- this is true for linux and macs -->
+  <condition property="current.os.isunix">
+    <os family="unix"/>
+  </condition>
+  
+  <condition property="current.os.isunixnotmac">
+    <and>
+      <os family="unix"/>
+      <not>
+	<os family="mac"/>
+      </not>
+    </and>
+  </condition>
+  <condition property="current.os.ismac">
+    <os family="mac"/>
+  </condition>
+  
+  <condition property="current.os.iswindows">
+    <os family="windows"/>
+  </condition>
+
+  <condition property="collection.building.enabled">
+    <not>
+      <isset property="disable.collection.building"/>
+    </not>
+  </condition>
+
+  <condition property="collection.building.enabled.windows">
+    <and>
+      <isset property="collection.building.enabled"/>
+      <isset property="current.os.iswindows"/>
+    </and>
+  </condition>
+  
+  <condition property="collection.building.enabled.unix">
+    <and>
+      <isset property="collection.building.enabled"/>
+      <isset property="current.os.isunix"/>
+    </and>
+  </condition>
+  
+  <condition property="independent-indexers">
+    <isset property="disable.collection.building"/>
+  </condition>
+    
+  <!-- ============= Base dirs for each package and component ============ -->
+  <property name="src.applet.home" value="${src.home}/org/greenstone/applet"/>
+  <property name="src.gsdl3.home" value="${src.home}/org/greenstone/gsdl3"/>
+  <property name="anttasks.home" value="${src.home}/org/greenstone/anttasks"/>
+  <property name="gs2build.home" value="${basedir}/gs2build"/>
+  <property name="gli.home" value="${basedir}/gli"/>
+  <property name="javagdbm.home" value="${src.packages.home}/javagdbm"/>
+
+  <!--<property name="indexers.home" value="${basedir}/src/packages/indexers">-->
+  <condition property="indexers.home" value="${basedir}/src/packages/indexers">
+    <isset property="disable.collection.building"/>
+  </condition>
+  <condition property="indexers.home" value="${gs2build.home}/indexers">
+    <not>
+      <isset property="disable.collection.building"/>
+    </not>
+  </condition>
+
+  <property name="mg.home" value="${indexers.home}/mg"/>
+  <property name="mgpp.home" value="${indexers.home}/mgpp"/>
+  <property name="lucene.home" value="${indexers.home}/lucene-gs"/>
+
+
+<!--  ==================== Compilation Control Options ==================== -->
+
+<!--
+
+  These properties control option settings on the Javac compiler when it
+  is invoked using the <javac> task.
+
+  compile.debug        Should compilation include the debug option?
+
+  compile.deprecation  Should compilation include the deprecation option?
+
+  compile.optimize     Should compilation include the optimize option?
+
+-->
+
+  <property name="compile.debug"       value="true"/>
+  <property name="compile.deprecation" value="true"/>
+  <property name="compile.optimize"    value="true"/>
+
+<!--
+
+  Rather than relying on the CLASSPATH environment variable, Ant includes
+  features that makes it easy to dynamically construct the classpath you
+  need for each compilation.  The example below constructs the compile
+  classpath to include the servlet.jar file, as well as the other components
+  that Tomcat makes available to web applications automatically, plus anything
+  that you explicitly added.
+
+-->
+
+  <path id="compile.classpath">
+    <!-- Include all jar files and libraries in our jni lib directory -->
+    <pathelement location="${lib.jni}"/>
+    <fileset dir="${lib.jni}">
+      <include name="*.jar"/>
+    </fileset>
+    <!-- Include all jar files in our web lib directory -->
+    <pathelement location="${web.lib}"/>
+    <fileset dir="${web.lib}">
+      <include name="*.jar"/>
+    </fileset>
+    
+    <!-- Include the axis jar files -->
+    <!--<fileset dir="${basedir}/comms/soap/axis/lib">
+      <include name="*.jar"/>
+    </fileset>-->
+    
+    <!-- include the jar files from the source packages -->
+    <!-- mg and mgpp get installed into lib/jni but they may not be there yet
+    so we add them in by name -->
+    <pathelement location="${lib.jni}/mg.jar"/>
+    <pathelement location="${lib.jni}/mgpp.jar"/>
+    
+    <!-- Include all elements that Tomcat exposes to applications -->
+    <pathelement location="${catalina.home}/common/classes"/>
+    <fileset dir="${catalina.home}/common/endorsed">
+      <include name="*.jar"/>
+    </fileset>
+    <fileset dir="${catalina.home}/common/lib">
+      <include name="*.jar"/>
+    </fileset>
+    <pathelement location="${catalina.home}/shared/classes"/>
+    <fileset dir="${catalina.home}/shared/lib">
+      <include name="*.jar"/>
+    </fileset>
+  </path>
+
+  <path id="local.tomcat.classpath">
+    <!-- explicitly include the jni java wrappers in the classpath -->
+    <pathelement location="${lib.jni}"/>
+    <fileset dir="${lib.jni}">
+      <include name="*.jar"/>
+    </fileset>
+  </path>
+  
+  <path id="local.tomcat.path">
+    <pathelement location="${basedir}/bin/script"/>
+    <pathelement location="${basedir}/bin"/>
+    <pathelement location="${lib.jni}"/>
+    <pathelement path="${env.PATH}"/>
+    <pathelement path="${env.Path}"/>
+  </path>
+
+  <target name="test-setup">
+    <echo>ant java version=${ant.java.version}</echo>
+    <echo>is unix : ${current.os.isunix}</echo>
+    <echo>is mac : ${current.os.ismac}</echo>
+    <echo>is unixnotmac : ${current.os.isunixnotmac}</echo>
+    <echo>is windows : ${current.os.iswindows}</echo>
+    <echo>os.unix: ${os.unix}</echo>
+  </target>
+<!-- ==================== Primary and Global Targets ============================= -->
+
+  <!-- add comments about using xxx-core, xxx-packages if only want certain parts?? -->
+
+  <target name="prepare" depends="accept-properties,init,prepare-core,prepare-packages,prepare-gs2building,prepare-tomcat,prepare-axis,prepare-web,prepare-collections"
+    description="Use this when you first checkout the code: 'ant prepare install'. This will do some additional cvs checkouts and downloads, so you need to be online to run this.">
+    <!-- make sure .sh files are executable -->
+    <chmod dir="${basedir}" perm="ugo+rx" 
+      includes="*.sh"/>
+    <chmod dir="${basedir}/bin/script" perm="ugo+rx" 
+      includes="*.sh,*.pl"/>
+  </target>
+  <target name="install" depends="init,install-indexer-files,configure,configure-c++,compile" 
+    description="Install Greenstone 3. Use this when you first checkout the code: 'ant prepare install'."/>
+  
+  <target name="cvsupdate" depends="init,cvsupdate-packages,cvsupdate-core,cvsupdate-gs2building,cvsupdate-web"
+    description="Do a cvs update for all sources. Doesn't recompile the code. You need to be online to run this."/>
+
+  <target name="configure-c++" depends="init,configure-packages,configure-core,configure-gs2building"
+    description="Configure any C/C++ package code and gs2building code if necessary"/>
+  
+  <target name="configure" depends="init,configure-tomcat,configure-web"
+    description="Configure the installation. Includes setting up config files. Should be re-run if you change the build.properties file."/>
+
+  <target name="clean" depends="init,clean-packages,clean-core,clean-gs2building"
+    description="Remove all old compiled code. Includes core, packages and gs2building if necessary"/>
+  
+  <target name="compile" depends="init,compile-web,compile-packages,compile-core,compile-gs2building"
+    description="Compile all the source code, includes core, packages and gs2building if necessary. Copy jar files and executables to their correct places."/>
+    
+  <target name="update" depends="init,cvsupdate,clean,configure,configure-c++,compile" 
+    description="Update (thru CVS) all the source (including core, packages and gs2building), then clean, configure and recompile."/>
+
+  <target name="start" depends="init,start-tomcat"
+    description="Startup the Tomcat server." />
+
+  <target name="stop" depends="init,stop-tomcat" 
+    description="Shutdown the Tomcat server."/>
+  
+  <target name="restart" description="Shutdown and restart Tomcat"  depends="init,stop,start"/>
+
+
+<!-- =========== Help targets ===================================  -->
+  
+  <property name="install-command" value="ant [options] prepare install"/>
+  
+  <target name="usage" description="Print a help message">
+    <echo message="  Execute 'ant -projecthelp' for a list of targets."/>
+    <echo message="  Execute 'ant -help' for Ant help."/>
+    <echo>To install Greenstone3, run '${install-command}'. 
+There are properties defined in build.properties. The install process will ask you if these properties are set correctly. To avoid this prompt, use the '-Dproperties.accepted=yes' option.
+To log the output, use the '-logfile build.log' option.
+The README.txt file has more information about the ant targets and install process.
+    </echo>
+  </target>
+  
+  <target name="help" depends="usage" description="Print a help message"/>
+  
+  <target name="debug" depends="init" description="Display all the currently used properties">
+    <echoproperties/>
+  </target>
+
+<!-- ====== initialization and setup targets ================== -->
+
+  <target name="accept-properties" unless="properties.accepted">
+    <input addproperty="properties.ok" validargs="y,n">The following properties (among others) are being used from a build.properties file found in this directory:
+tomcat.server=${tomcat.server}
+tomcat.port=${tomcat.port} 
+tomcat.installed.path=${tomcat.installed.path} (this is the location of Tomcat's base dir if it is already installed)
+proxy.host=${proxy.host}
+proxy.port=${proxy.port}
+If these are not acceptable, please change them and rerun this target. Continue [y/n]? />
+    </input>
+    <condition property="do.abort"> 
+      <equals arg1="n" arg2="${properties.ok}"/>
+    </condition>
+    <fail if="do.abort">Build aborted by user. Please change your properties settings and re-run the target</fail>
+  </target>
+
+  <target name="check-cvsroot">
+    <condition property="cvsroot.notset">
+      <or>
+	<not>
+	  <isset property="env.CVSROOT"/>
+	</not>
+	<equals arg1="" arg2="${env.CVSROOT}"/>
+      </or>
+    </condition>
+    <fail if="cvsroot.notset" message="You need to set the CVSROOT variable"/>
+  </target>
+
+  <!-- this sets up some initial properties -->
+  <target name="init">
+
+    <condition property="java.too.old">
+      <or>
+	<equals arg1="1.1" arg2="${ant.java.version}"/>
+	<equals arg1="1.2" arg2="${ant.java.version}"/>
+	<equals arg1="1.3" arg2="${ant.java.version}"/>
+      </or>
+    </condition>
+    <fail if="java.too.old" message="You need Java 1.4 or greater to run Greenstone 3"/>
+    
+    <available file="${indexers.home}" property="indexers.present"/>
+    <available file="${basedir}/gli" property="gli.present"/>
+    <available file="${basedir}/gs2build" property="gs2build.present"/>
+
+    <condition property="tomcat.islocal">
+      <or>
+	<not>
+	  <isset property="tomcat.installed.path"/>
+	</not>
+	<equals arg1="" arg2="${tomcat.installed.path}"/>
+      </or>
+    </condition>
+    
+      <echo>tomcat.port:${tomcat.port}, gli.present:${gli.present} gs2build.present=${gs2build.present} gsdl2.installed.path = ${gsdl2.installed.path}</echo>
+    <condition property="proxy.present">
+      <and>
+	<isset property="proxy.host"/>
+	<not>
+	  <equals arg1="" arg2="${proxy.host}"/>
+	</not>
+      </and>
+    </condition>
+
+    <condition property="need.macos.extra">
+      <and>
+	<isset property="current.os.ismac"/>
+	<not>
+	  <isset property="disable.collection.building"/>
+	</not>
+      </and>
+    </condition>
+  </target>
+
+  <target name="setup-proxy" depends="init" if="proxy.present">
+    <condition property="ask.user">
+      <or>
+	<equals arg1="" arg2="${proxy.user}"/>
+	<equals arg1="" arg2="${proxy.password}"/>
+      </or>
+    </condition>
+    <getuserandpassword message="Using proxy: ${proxy.host}:${proxy.port}" if="ask.user" username="${proxy.user}" userproperty="proxy.username" pwordproperty="proxy.password"/>
+    <mysetproxy proxyhost="${proxy.host}" proxyport="${proxy.port}" proxyuser="${proxy.username}" proxypassword="${proxy.password}"/>
+  </target>
+     
+ <!-- ========== Web app Targets ================================ -->
+  
+  <target name="prepare-web" depends="init,configure-java-version">
+    <mkdir dir="${web.home}/applet"/>
+    <mkdir dir="${web.home}/logs"/>
+  </target>
+  
+  <!-- if we are using java 1.5, we need the xalan.jar file in web/WEB-INF/lib,  but if we are using java 1.4, we can't have it there -->
+  <target name="configure-java-version" depends="init"
+    description="Run this target if you have changed the default version of java since installing greenstone3">
+    <condition property="need.xalan.jar">
+      <equals arg1="1.5" arg2="${ant.java.version}"/>
+    </condition>
+    <antcall target="activate-xalan-jar"/>
+    <antcall target="deactivate-xalan-jar"/>
+  </target>
+  
+  <target name="activate-xalan-jar" if="need.xalan.jar">
+    <copy file="${web.lib}/xalan.jar.tmp" tofile="${web.lib}/xalan.jar"/>
+  </target>
+  
+  <target name="deactivate-xalan-jar" unless="need.xalan.jar">
+    <delete file="${web.lib}/xalan.jar"/>
+  </target>
+
+  <target name="prepare-collections" depends="init">
+    <property name="collect.dir" value="${web.home}/sites/localsite/collect"/>
+    <!-- gs2mgdemo -->
+    <unzip src="${collect.dir}/gs2mgdemo/import.zip" 
+      dest="${collect.dir}/gs2mgdemo"/>
+    <unzip src="${collect.dir}/gs2mgdemo/metadata.zip" 
+      dest="${collect.dir}/gs2mgdemo"/>
+    <unzip src="${collect.dir}/gs2mgdemo/index/index.zip" 
+      dest="${collect.dir}/gs2mgdemo/index"/>
+    <delete file="${collect.dir}/gs2mgdemo/import.zip"/>
+    <delete file="${collect.dir}/gs2mgdemo/metadata.zip"/>
+    <delete file="${collect.dir}/gs2mgdemo/index/index.zip"/>
+    <!-- gs2mgppdemo -->
+    <unzip src="${collect.dir}/gs2mgppdemo/import.zip" 
+      dest="${collect.dir}/gs2mgppdemo"/>
+    <unzip src="${collect.dir}/gs2mgppdemo/metadata.zip" 
+      dest="${collect.dir}/gs2mgppdemo"/>
+    <unzip src="${collect.dir}/gs2mgppdemo/index/index.zip" 
+      dest="${collect.dir}/gs2mgppdemo/index"/>
+    <delete file="${collect.dir}/gs2mgppdemo/import.zip"/>
+    <delete file="${collect.dir}/gs2mgppdemo/metadata.zip"/>
+    <delete file="${collect.dir}/gs2mgppdemo/index/index.zip"/>
+    <!-- gberg -->
+    <unzip src="${collect.dir}/gberg/index/index.zip" 
+      dest="${collect.dir}/gberg/index"/>
+    <delete file="${collect.dir}/gberg/index/index.zip"/>
+  </target>
+
+  
+  <target name="configure-web" depends="init"
+    description="Configure only the web app config files">
+    <!-- we want a unix path in the global.properties file -->
+    <pathconvert targetos="unix" property="src.gsdl3.home.unix">
+      <path path="${web.home}"/>
+    </pathconvert>
+    <filter token="gsdl3home" value="${src.gsdl3.home.unix}"/>
+    <filter token="gsdl3version" value="${app.version}"/>
+    <filter token="tomcat.server" value="${tomcat.server}"/>
+    <filter token="tomcat.port" value="${tomcat.port}"/>
+    <copy file="${basedir}/resources/java/global.properties.in" tofile="${web.classes}/global.properties" filtering="true" overwrite="true"/> 
+    <copy file="${basedir}/resources/java/log4j.properties.in" tofile="${web.classes}/log4j.properties" filtering="true" overwrite="true"/> 
+    <chmod file="${web.classes}/global.properties" perm="600"/>
+    <chmod file="${web.classes}/log4j.properties" perm="600"/>
+  </target>
+
+  <target name="compile-web" depends="init">
+    <javac srcdir="${web.classes}"
+      destdir="${web.classes}"
+      debug="${compile.debug}"
+      deprecation="${compile.deprecation}"
+      optimize="${compile.optimize}">
+      <classpath>
+	<path refid="compile.classpath"/>
+      </classpath>
+    </javac>
+  </target>
+
+  <target name="cvsupdate-web" unless="nocvs.mode">
+    <cvs command="update -dP" dest="${web.home}"/>
+  </target>
+
+  <target name="update-web" depends="init,cvsupdate-web,configure-web"
+    description="update only the web stuff (config files)"/>
+
+
+<!-- ======================= Tomcat Targets ========================== -->
+  
+  <!-- this target downloads and installs Tomcat -->
+  <!-- we download tomcat and the compat module - its needed for 1.4, and doesn't seem to harm 1.5 -->
+  <target name="prepare-tomcat" depends="init,setup-proxy" if="tomcat.islocal">
+
+    <!-- check that packages dir is there -->
+    <mkdir dir="${packages.home}"/>
+    <get src="http://www.greenstone.org/gs3files/apache-tomcat-5.5.12.zip"
+      dest="${packages.home}/apache-tomcat-5.5.12.zip"
+      usetimestamp="true"/>
+    <unzip src="${packages.home}/apache-tomcat-5.5.12.zip" 
+      dest="${packages.home}"/>
+    <get src="http://www.greenstone.org/gs3files/apache-tomcat-5.5.12-compat.zip"
+      dest="${packages.home}/apache-tomcat-5.5.12-compat.zip"
+      usetimestamp="true"/>
+    <unzip src="${packages.home}/apache-tomcat-5.5.12-compat.zip" 
+      dest="${packages.home}"/>
+    <!-- delete any existing tomcat -->
+    <delete dir="${packages.home}/tomcat"/>
+    <move todir="${packages.home}/tomcat">
+      <fileset dir="${packages.home}/apache-tomcat-5.5.12"/>
+    </move>
+    <copy file="${basedir}/resources/tomcat/setclasspath.bat"
+      tofile="${packages.home}/tomcat/bin/setclasspath.bat"
+      overwrite="true"/>
+    <copy file="${basedir}/resources/tomcat/setclasspath.sh"
+      tofile="${packages.home}/tomcat/bin/setclasspath.sh"
+      overwrite="true"/>
+    <!-- make sure we have execute permission for the .sh files -->
+    <chmod dir="${packages.home}/tomcat/bin" perm="ugo+rx" 
+      includes="*.sh"/>   
+  </target>
+  
+  <target name="configure-tomcat" depends="init,configure-tomcat-local,configure-tomcat-external"/>
+  
+  <target name="configure-tomcat-local" depends="init" if="tomcat.islocal">
+    <!-- re-setup the server.xml file -->
+    <copy file="${basedir}/resources/tomcat/server.xml" tofile="${packages.home}/tomcat/conf/server.xml" overwrite="true">
+      <filterset>
+	<filter token="port" value="${tomcat.port}"/>
+	<filter token="shutdown-port" value="${tomcat.shutdown.port}"/>
+      </filterset>
+    </copy>
+    <!-- set up the greenstone3 context -->
+    <copy file="${basedir}/resources/tomcat/greenstone3.xml" tofile="${packages.home}/tomcat/conf/Catalina/localhost/greenstone3.xml" overwrite="true">
+      <filterset>
+	<filter token="gsdl3webhome" value="${basedir}/web"/>
+      </filterset>
+    </copy>
+  </target>
+
+  <target name="configure-tomcat-external" depends="init" unless="tomcat.islocal">
+    <!-- re-setup the server.xml file -->
+    <!-- need to edit the config file, or do we get the user to do this???-->
+  </target>
+    
+  <target name="start-tomcat" description="Startup only Tomcat" depends="init" if="tomcat.islocal">
+   <property name="tomcat.classpath" refid="local.tomcat.classpath"/>
+    <property name="tomcat.path" refid="local.tomcat.path"/>
+    <property name="catalina.opts" value="-Djava.util.prefs.syncInterval=2000000 -DGSDL3HOME=$GSDL3HOME -DGSDLOS=$GSDLOS -DPATH=$PATH -Xmx400M"/>
+    <exec executable="${catalina.home}/bin/startup.sh" os="${os.unix}" dir="${catalina.home}/bin" spawn="false">
+      <!--<env key="GSDLOS" value="linux"/> do we need this?? -->
+      <env key="GSDL3HOME" value="${basedir}"/>
+      <env key="PATH" path="${tomcat.path}"/>
+      <env key="CATALINA_OPTS" value="${catalina.opts}"/>
+      <env key="CATALINA_HOME" value="${catalina.home}"/>
+      <env key="CLASSPATH" path="${tomcat.classpath}"/>
+      <env key="LD_LIBRARY_PATH" path="${env.LD_LIBRARY_PATH}:${lib.jni}"/>
+      <env key="DYLD_LIBRARY_PATH" path="${env.DYLD_LIBRARY_PATH}:${lib.jni}:${gdbm.installed.path}/lib"/> <!-- for mac os -->
+    </exec>
+    <exec executable="${catalina.home}/bin/startup.bat" os="${os.windows}" dir="${catalina.home}/bin" spawn="true">
+      <env key="GSDLOS" value="windows"/>
+      <env key="GSDL3HOME" value="${basedir}"/>
+      <env key="Path" path="${tomcat.path}"/>
+      <env key="PATH" path="${tomcat.path}"/>
+      <env key="CATALINA_OPTS" value="${catalina.opts}"/>
+      <env key="CLASSPATH" path="${tomcat.classpath}"/>
+    </exec>
+    <!-- wait for the server to startup in case other targets need it running -->
+    <waitfor maxwait="5" maxwaitunit="second">
+      <and>
+	<socket server="${tomcat.server}" port="${tomcat.port}"/>
+	<http url="http://${tomcat.server}:${tomcat.port}${app.path}/index.html"/>
+      </and>
+    </waitfor>
+  </target>
+  <!-- windows: do we want to launch a webrowser?? -->
+  <target name="stop-tomcat" description="Shutdown only Tomcat" depends="init" if="tomcat.islocal">
+    <exec executable="${catalina.home}/bin/shutdown.sh" os="${os.unix}" dir="${catalina.home}/bin" spawn="false">
+      <env key="CATALINA_HOME" value="${catalina.home}"/>
+    </exec>
+    <exec executable="${catalina.home}/bin/shutdown.bat" os="${os.windows}" dir="${catalina.home}/bin" spawn="false"/>
+  </target>
+
+  <target name="restart-tomcat" description="Shutdown and restart only Tomcat" depends="init,stop-tomcat,start-tomcat"/>
+
+  <target name="setup-catalina-ant-tasks">
+    <!-- Configure the custom Ant tasks for the Tomcat Manager application -->
+    <taskdef name="deploy"    classname="org.apache.catalina.ant.DeployTask"
+      classpath="${catalina.home}/server/lib/catalina-ant.jar"/>
+    <taskdef name="list"      classname="org.apache.catalina.ant.ListTask"
+      classpath="${catalina.home}/server/lib/catalina-ant.jar"/>
+    <taskdef name="reload"    classname="org.apache.catalina.ant.ReloadTask"
+      classpath="${catalina.home}/server/lib/catalina-ant.jar"/>
+    <taskdef name="resources" classname="org.apache.catalina.ant.ResourcesTask"
+      classpath="${catalina.home}/server/lib/catalina-ant.jar"/>
+    <taskdef name="roles"     classname="org.apache.catalina.ant.RolesTask"
+      classpath="${catalina.home}/server/lib/catalina-ant.jar"/>
+    <taskdef name="start"     classname="org.apache.catalina.ant.StartTask"
+      classpath="${catalina.home}/server/lib/catalina-ant.jar"/>
+    <taskdef name="stop"      classname="org.apache.catalina.ant.StopTask"
+      classpath="${catalina.home}/server/lib/catalina-ant.jar"/>
+    <taskdef name="undeploy"  classname="org.apache.catalina.ant.UndeployTask"
+      classpath="${catalina.home}/server/lib/catalina-ant.jar"/>
+  </target>
+
+
+
+
+
+
+<!-- ======================= ant Targets ============================ --> 
+  <target name="prepare-ant" depends="init">
+    <get src="http://www.greenstone.org/gs3files/apache-ant-1.7.0-bin.zip"
+      dest="${packages.home}/apache-ant-1.7.0-bin.zip"
+      usetimestamp="true"/>
+    <unzip src="${packages.home}/apache-ant-1.7.0-bin.zip"
+      dest="${packages.home}"/>
+    <move todir="${packages.home}/ant">
+      <fileset dir="${packages.home}/apache-ant-1.7.0"/>
+    </move>
+  </target>
+
+<!-- ======================= Axis Targets ============================ --> 
+
+  <target name="prepare-axis" depends="init">
+    <get src="http://www.greenstone.org/gs3files/axis-bin-1_2_1.zip"
+      dest="${packages.home}/axis-bin-1_2_1.zip"
+      usetimestamp="true"/>
+    <unzip src="${packages.home}/axis-bin-1_2_1.zip"
+      dest="${packages.home}"/>
+    <move todir="${packages.home}/axis">
+      <fileset dir="${packages.home}/axis-1_2_1"/>
+    </move>
+    <!-- install axis into greenstone web app -->
+    <copy todir="${web.lib}">
+      <fileset dir="${packages.home}/axis/webapps/axis/WEB-INF/lib">
+	<include name="*.jar"/>
+      </fileset>
+    </copy>
+    <copy todir="${web.home}">
+      <fileset dir="${packages.home}/axis/webapps/axis/">
+	<include name="*.jsp"/>
+	<include name="*.jws"/>
+      </fileset>
+    </copy>
+    <copy tofile="${web.home}/axis.html" file="${packages.home}/axis/webapps/axis/index.html"/>
+    <copy todir="${web.classes}">
+      <fileset dir="${packages.home}/axis/webapps/axis/WEB-INF/classes">
+	<include name="*.properties"/>
+      </fileset>
+    </copy>
+  </target>
+
+  <target name="soap-deploy-site" depends="init,get-sitename,get-siteuri,create-deployment-files,deploy-site"
+    description="Deploy a SOAP web service for a local Greenstone site. Tomcat must be running for this to work."/>
+  
+  <target name="deploy-site">
+    <java classname="org.apache.axis.client.AdminClient">
+      <classpath refid="compile.classpath"/>
+      <arg value="-l"/>
+      <arg value="http://${tomcat.server}:${tomcat.port}${app.path}/servlet/AxisServlet"/>
+      <arg file="${basedir}/resources/soap/${axis.sitename}.wsdd"/>
+    </java>    
+  </target>
+  
+  <target name="soap-undeploy-site" depends="get-sitename"
+    description="Undeploy a SOAP web service for a local Greenstone site. Tomcat must be running for this to work.">
+    <java classname="org.apache.axis.client.AdminClient">
+      <classpath refid="compile.classpath"/>
+      <arg value="-l"/>
+      <arg value="http://${tomcat.server}:${tomcat.port}${app.path}/servlet/AxisServlet"/>
+      <arg file="${basedir}/resources/soap/undeploy-${axis.sitename}.wsdd"/>
+    </java>
+  </target>
+
+  <!-- this target used to deploy the preprepared localsite server  -->
+  <target name="deploy-localsite" depends="init" 
+    description="Deploy the SOAP server for localsite. Will start and stop Tomcat.">
+    <antcall target="start-tomcat"/>
+    <antcall target="deploy-site">
+      <param name="axis.sitename" value="localsite"/>
+    </antcall>
+    <antcall target="stop-tomcat"/>
+  </target>
+  
+  <target name="get-sitename" unless="axis.sitename">
+    <input addproperty="axis.sitename" message="What site? (press enter for default:localsite)" defaultvalue="localsite"/>
+  </target>
+
+  <target name="get-siteuri" depends="get-sitename" unless="axis.siteuri">
+    <input addproperty="axis.siteuri" message="What name do you want the service to have? (press enter for default:${axis.sitename})" defaultvalue="${axis.sitename}"/>
+    <echo>${axis.sitename}, ${axis.siteuri}</echo>
+  </target>
+
+  <target name="check-deployment-files" depends="get-sitename">
+    <condition property="deploy.exists">
+      <and>
+	<available file="${basedir}/resources/soap/${axis.sitename}.wsdd"/>
+	<available file="${basedir}/resources/soap/undeploy-${axis.sitename}.wsdd"/>
+	<available file="${web.classes}/org/greenstone/gsdl3/SOAPServer${axis.sitename}.class"/>
+      </and>
+    </condition>
+   </target> 
+
+  <target name="create-deployment-files" depends="get-sitename,get-siteuri,check-deployment-files" 
+    if="axis.sitename" unless="deploy.exists">
+    <filter token="sitename" value="${axis.sitename}"/>
+    <filter token="siteuri" value="${axis.siteuri}"/>
+    <copy file="${basedir}/resources/soap/site.wsdd.template"
+      tofile="${basedir}/resources/soap/${axis.sitename}.wsdd"
+      filtering="true"/>
+     <copy file="${basedir}/resources/soap/undeploy-site.wsdd.template"
+      tofile="${basedir}/resources/soap/undeploy-${axis.sitename}.wsdd"
+      filtering="true"/>
+    <!-- create the java files and compile them -->
+    <copy file="${basedir}/resources/java/SOAPServer.java.in"
+      tofile="${src.gsdl3.home}/SOAPServer${axis.sitename}.java"
+      filtering="true"/>
+    <mkdir dir="${build.home}"/>
+    <javac srcdir="${src.home}"
+      destdir="${build.home}" 
+      debug="${compile.debug}"
+      deprecation="${compile.deprecation}"
+      optimize="${compile.optimize}">
+      <classpath refid="compile.classpath"/>
+      <include name="org/greenstone/gsdl3/SOAPServer${axis.sitename}.java" />
+    </javac>
+    <mkdir dir="${web.classes}/org/greenstone/gsdl3"/>
+    <copy file="${build.home}/org/greenstone/gsdl3/SOAPServer${axis.sitename}.class" tofile="${web.classes}/org/greenstone/gsdl3/SOAPServer${axis.sitename}.class" />
+  </target>
+    
+
+<!-- ====================== Core targets ============================== -->
+<!-- core targets refer to the core gsdl3 java src -->
+  
+  <target name="prepare-core" unless="nocvs.mode">
+    <!-- just get rid of empty directories-->
+    <cvs command="update -P"/>
+  </target>
+  
+  <target name="configure-core"/>
+
+  <target name="update-core" depends="init,cvsupdate-core,clean-core,compile-core"
+    description="Update only the Greenstone core" />
+  
+  <target name="cvsupdate-core" unless="nocvs.mode">
+    <cvs command="update -l"/>
+    <cvs command="update -dP bin comms dist-resources docs lib resources src winutil"/>
+  </target>
+
+  <target name="clean-core"
+    description="Clean only the Greenstone core">
+    <delete dir="${build.home}"/>
+  </target>
+
+   <target name="compile-core" depends="init" 
+    description="Compile only the Greenstone core">
+    <mkdir dir="${build.home}"/>
+    <javac srcdir="${src.home}"
+      destdir="${build.home}"
+      debug="${compile.debug}"
+      deprecation="${compile.deprecation}"
+      optimize="${compile.optimize}">
+      <classpath>
+	<path refid="compile.classpath"/>
+      </classpath>
+    </javac>
+    <jar destfile="${build.home}/gsdl3.jar">
+      <fileset dir="${build.home}">
+	<include name="org/greenstone/gsdl3/**"/>
+	<exclude name="**/Test.class"/>
+      </fileset>
+      <manifest>
+	<attribute name="Built-By" value="${user.name}" />
+      </manifest>
+    </jar>
+    <copy file="${build.home}/gsdl3.jar" todir="${web.lib}"/>
+    <!-- copy the localsite server in case we need it -->
+    <copy file="${build.home}/org/greenstone/gsdl3/SOAPServerlocalsite.class" tofile="${web.classes}/org/greenstone/gsdl3/SOAPServerlocalsite.class" />
+
+    <jar destfile="${build.home}/GAI.jar">
+      <fileset dir="${build.home}">
+	<include name="org/greenstone/admin/**"/>
+      </fileset>
+      <manifest>
+	<attribute name="Built-By" value="${user.name}" />
+      </manifest>
+    </jar>
+      
+    <jar destfile="${build.home}/phind.jar">
+      <fileset dir="${build.home}">
+	<include name="org/greenstone/applet/phind/**"/>
+      </fileset>
+      <manifest>
+	<attribute name="Built-By" value="${user.name}" />
+      </manifest>
+    </jar>
+    <mkdir dir="${web.applet}"/>
+    <copy file="${build.home}/phind.jar" todir="${web.applet}"/>
+    <!-- phind also needs xercesImpl.jar and xml-apis.jar to be in web/applet -->
+    <copy file="${packages.home}/tomcat/common/endorsed/xercesImpl.jar" todir="${web.applet}"/>
+    <copy file="${packages.home}/tomcat/common/endorsed/xml-apis.jar" todir="${web.applet}"/>
+    <jar destfile="${build.home}/anttasks.jar">
+      <fileset dir="${build.home}">
+	<include name="org/greenstone/anttasks/**"/>
+      </fileset>
+      <manifest>
+	<attribute name="Built-By" value="${user.name}" />
+      </manifest>
+    </jar>
+    <copy file="${build.home}/anttasks.jar" todir="${basedir}/lib/java"/>
+    <jar destfile="${build.home}/gsdl3test.jar">
+      <fileset dir="${build.home}">
+	<include name="org/greenstone/gsdl3/**/*Test.class"/>
+	<include name="org/greenstone/testing/**"/>
+      </fileset>
+      <manifest>
+	<attribute name="Built-By" value="${user.name}" />
+      </manifest>
+    </jar>
+    <jar destfile="${build.home}/server.jar">
+      <fileset dir="${build.home}">
+	<include name="org/greenstone/server/**"/>
+      </fileset>
+      <fileset file="${basedir}/resources/java/server.properties"/>
+      <manifest>
+	<attribute name="Built-By" value="${user.name}"/>
+      </manifest>
+    </jar>
+    <copy file="${build.home}/server.jar" todir="${basedir}"/>
+  </target>
+ 
+<!-- ================== Packages targets ================================ -->
+  <!-- these targets refer to the greenstone source packages - these need 
+  updating less often, so are in  separate targets to the core -->
+  <target name="prepare-packages" depends="init,prepare-indexers"/>
+  
+  <target name="checkout-indexers" depends="check-cvsroot,init" if="independent-indexers" unless="nocvs.mode">
+    <cvs command="checkout -P" package="indexers" dest="${src.packages.home}"/>
+  </target>
+  
+  <target name="prepare-indexers" depends="init" if="independent-indexers" unless="indexers.present">
+    <antcall target="checkout-indexers"/>
+  </target>
+
+  <target name="update-packages" depends="init,cvsupdate-packages,configure-packages,clean-packages,compile-packages"
+    description="Update only the source packages"/>
+
+  <target name="cvsupdate-packages" unless="nocvs.mode"> 
+    <cvs command="update -dP" dest="${src.packages.home}"/>
+  </target>
+  
+  <target name="configure-packages" depends="init,configure-javagdbm,configure-indexers" 
+    description="Configure only the packages."/>
+  
+  <target name="configure-javagdbm">
+    <echo>
+      Configuring JavaGDBM
+    </echo>
+    <exec executable="${javagdbm.home}/configure" os="${os.linux},${os.solaris}"
+      dir="${javagdbm.home}">
+      <arg value="--prefix=${basedir}"/>
+      <arg value="--libdir=${lib.jni}"/>
+    </exec>    
+    <exec executable="${javagdbm.home}/configure" os="${os.mac}"
+      dir="${javagdbm.home}">
+      <arg value="--prefix=${basedir}"/>
+      <arg value="--libdir=${lib.jni}"/>
+     <arg value="--with-gdbm=${gdbm.installed.path}"/>
+    </exec>    
+    
+  </target>
+  <target name="configure-indexers" depends="init" if="independent-indexers">
+    <echo>
+      Configuring Indexers
+    </echo>
+    <exec executable="${indexers.home}/configure" os="${os.unix}"
+      dir="${indexers.home}">
+      <arg value="--prefix=${basedir}"/>
+      <arg value="--libdir=${lib.jni}"/>
+    </exec>          
+  </target>
+
+  <target name="clean-packages" depends="init,clean-javagdbm,clean-indexers" description="Clean only the packages"/>
+
+  <target name="clean-javagdbm" depends="init">
+    <exec executable="make" os="${os.unix}"
+      dir="${javagdbm.home}">
+      <arg value="clean"/>
+    </exec>
+  </target>
+  
+  <target name="clean-indexers" depends="init" if="independent-indexers">
+    <exec executable="make" os="${os.unix}"
+      dir="${indexers.home}">
+      <arg value="clean"/>
+    </exec>
+    <exec executable="${indexers.home}/winMake.bat" os="${os.windows}"
+       dir="${indexers.home}">
+       <arg value="clean"/>
+    </exec>
+
+  </target>
+   
+  <target name="compile-packages"
+    description="Compile only the source packages">    
+    <!-- javagdbm -->
+    <exec executable="make" os="${os.unix}"
+      dir="${javagdbm.home}">
+    </exec>
+    <exec executable="make" os="${os.unix}"
+      dir="${javagdbm.home}">
+      <arg value="install"/>
+    </exec>
+    <!-- windows: just the java stuff. -->
+    <exec executable="${javagdbm.home}/winMake.bat" os="${os.windows}"
+      dir="${javagdbm.home}">
+      <arg value="compile"/>
+      <arg value="javaonly"/>
+    </exec>
+    <!-- install the jar file -->
+    <copy file="${javagdbm.home}/javagdbm.jar" todir="${lib.jni}"/>
+    
+    <!-- Indexers -->
+    <!-- this may be in gs2build - we will be recompiling, but never mind -->
+    <exec executable="make" os="${os.unix}"
+      dir="${indexers.home}">
+    </exec>
+    <exec executable="make" os="${os.unix}"
+      dir="${indexers.home}">
+      <arg value="install"/>
+    </exec>
+    <exec executable="${indexers.home}/winMake.bat" os="${os.windows}"
+       dir="${indexers.home}">
+       <arg value="all"/>
+    </exec>
+    <exec executable="${indexers.home}/winMake.bat" os="${os.windows}"
+       dir="${indexers.home}">
+       <arg value="install"/>
+    </exec>
+    <!-- install the jar and jni files -->
+    <copy file="${mg.home}/mg.jar" todir="${lib.jni}"/>
+    <copy file="${mgpp.home}/mgpp.jar" todir="${lib.jni}"/>
+    <copy file="${lucene.home}/LuceneWrapper.jar" todir="${web.lib}"/>
+    <antcall target="install-jni-files"/>
+  </target>
+
+  <target name="install-jni-files" depends="init,install-jni-files-linux,install-jni-files-windows,install-jni-files-macos"/>
+
+  <target name="install-jni-files-linux" depends="init" if="current.os.isunixnotmac">
+    <copy file="${mg.home}/jni/libmgjni.so" todir="${lib.jni}"/>
+    <copy file="${mg.home}/jni/libmgpassjni.so" todir="${lib.jni}"/>
+    <copy file="${mgpp.home}/jni/libmgppjni.so" todir="${lib.jni}"/>
+    <copy file="${mgpp.home}/jni/libmgpppassjni.so" todir="${lib.jni}"/>
+  </target>
+  <target name="install-jni-files-windows" depends="init" if="current.os.iswindows">
+    <copy file="${mg.home}/jni/mgjni.dll" todir="${lib.jni}"/>
+    <copy file="${mg.home}/jni/mgpassjni.dll" todir="${lib.jni}"/>
+    <copy file="${mgpp.home}/jni/mgppjni.dll" todir="${lib.jni}"/>
+    <copy file="${mgpp.home}/jni/mgpppassjni.dll" todir="${lib.jni}"/>
+  </target>
+  <target name="install-jni-files-macos" depends="init" if="current.os.ismac">
+    <copy file="${mg.home}/jni/libmgjni.jnilib" todir="${lib.jni}"/>
+    <copy file="${mg.home}/jni/libmgpassjni.jnilib" todir="${lib.jni}"/>
+    <copy file="${mgpp.home}/jni/libmgppjni.jnilib" todir="${lib.jni}"/>
+    <copy file="${mgpp.home}/jni/libmgpppassjni.jnilib" todir="${lib.jni}"/>
+  </target>
+ 
+  <!-- ================== gs2building targets ===============-->
+
+
+  <target name="update-gs2building" if="collection.building.enabled" 
+    depends="init,cvsupdate-gs2building,rename-gs2build-files,configure-gs2building,clean-gs2building,compile-gs2building"
+    description="Update only the Greenstone 2 building components"/>
+
+  <target name="cvsupdate-gs2building" if="collection.building.enabled" depends="init,cvsupdate-gs2build,cvsupdate-gli" unless="nocvs.mode">
+  </target>
+  <target name="cvsupdate-gs2build" if="collection.building.enabled" depends="init" unless="nocvs.mode">
+    <!-- Note: can't do a -d update here cos it will get all of gsdl 
+     also, an update doesn't get new files, so we do a checkout instead. -->
+    <cvs command="checkout -P" package="gs2build" dest="${basedir}"/>
+  </target>
+  
+  <target name="cvsupdate-gli" if="collection.building.enabled" depends="init" unless="nocvs.mode">
+    <cvs command="update -dP" dest="${gli.home}"/>
+  </target>
+
+  <target name="prepare-gs2building" depends="init,prepare-gs2build,prepare-gli" if="collection.building.enabled">
+  </target>
+
+  <target name="checkout-gs2build" depends="check-cvsroot,init" if="collection.building.enabled" unless="nocvs.mode">
+    <echo>checking out gs2build</echo>
+    <cvs command="checkout -P" package="gs2build"/>
+  </target>
+
+  <target name="prepare-gs2build" depends="init" if="collection.building.enabled" unless="gs2build.present">
+    <antcall target="checkout-gs2build"/>
+    <antcall target="rename-gs2build-files"/>
+    <antcall target="unzip-windows-packages"/>
+    <antcall target="checkout-winbin"/>
+    <antcall target="get-windows-binaries"/>
+    <antcall target="delete-winbin"/>
+    <antcall target="get-macos-extra"/>
+  </target>
+
+  <target name="checkout-winbin" depends="init" if="current.os.iswindows" 
+    unless="nocvs.mode">
+    <cvs command="checkout -P" package="winbin"/>
+  </target>
+  
+  <target name="get-windows-binaries" depends="init" if="collection.building.enabled.windows">
+    <move todir="${gs2build.home}/bin/windows" failonerror="false">
+      <fileset dir="${basedir}/winbin/bin"/>
+    </move>
+  </target>
+  <target name="delete-winbin" depends="init" if="collection.building.enabled.windows">
+    <delete dir="${basedir}/winbin"/>
+  </target>
+  
+  <target name="unzip-windows-packages" depends="init" if="collection.building.enabled.windows">  
+    <unzip src="${gs2build.home}/packages/windows/gdbm/gdbm.zip"
+    dest="${gs2build.home}/packages/windows/gdbm"/>
+   <unzip src="${gs2build.home}/packages/windows/crypt/crypt.zip"
+    dest="${gs2build.home}/packages/windows/crypt"/>
+       <unzip src="${gs2build.home}/packages/windows/expat/expat.zip"
+    dest="${gs2build.home}/packages/windows/expat"/>
+   </target>
+  
+  <!-- downloads a good XML-Parser -->
+  <target name="get-macos-extra" depends="init" if="need.macos.extra">	
+      <get src="http://www.greenstone.org/gs3files/XML-Parser.tar.gz"
+      dest="${gs2build.home}/perllib/cpan/XML-Parser.tar.gz"
+      usetimestamp="true"/>
+  </target>  
+
+  <!-- untars the XML-Parser. need to do this after compiling in gs2build-->
+  <target name="install-macos-extra" depends="init" if="need.macos.extra">
+    <!-- make sure these directories are present, otherwise chmod craps out 
+    this chmod is needed in case we are unpacking for a second time -->
+    <mkdir dir="${gs2build.home}/perllib/cpan/perl-5.8"/>
+    <mkdir dir="${gs2build.home}/perllib/cpan/perl-5.6"/>
+    <chmod dir="${gs2build.home}/perllib/cpan/perl-5.8" perm="ug+w" includes="**"/>
+    <chmod dir="${gs2build.home}/perllib/cpan/perl-5.6" perm="ug+w" includes="**"/>
+    <untar src="${gs2build.home}/perllib/cpan/XML-Parser.tar.gz"
+      dest="${gs2build.home}/perllib/cpan/"
+      compression="gzip"/>
+  </target>
+
+  <target name="install-indexer-files" depends="init" unless="indexers.present">
+    <copy todir="${indexers.home}">
+      <fileset dir="${gs2build.home}/indexers" />
+    </copy>
+    <chmod file="${indexers.home}/configure" perm="a+x"/>
+  </target>
+
+  <target name="rename-gs2build-files" depends="rename-gs2build-files-unix,rename-gs2build-files-windows,gs2build-edit-setup-bat" if="collection.building.enabled"/>
+  
+  <target name="gs2build-edit-setup-bat" if="collection.building.enabled.windows">
+    <!-- we want a windows path in the setup.bat file -->
+    <pathconvert targetos="windows" property="gs2build.home.windows">
+      <path path="${gs2build.home}"/>
+    </pathconvert>
+    <move file="${gs2build.home}/setup.bat" tofile="${gs2build.home}/setup-tmp.bat">
+      <filterset>
+	<filter token="gsdlhome" value="${gs2build.home.windows}"/>
+     </filterset>
+    </move>  
+    <move file="${gs2build.home}/setup-tmp.bat" tofile="${gs2build.home}/setup.bat" />
+  </target>
+  
+  <target name="rename-gs2build-files-windows" if="collection.building.enabled.windows">
+    <property name="gs2build-extra.home" value="${gs2build.home}/gs2build-extra"/>
+    <copy file="${gs2build-extra.home}/lib.win32.mak" tofile="${gs2build.home}/lib/win32.mak"/>
+    <copy file="${gs2build-extra.home}/win32.mak" tofile="${gs2build.home}/win32.mak"/>
+    <copy file="${gs2build-extra.home}/setup.bat" tofile="${gs2build.home}/setup.bat"/>
+  </target> 
+  
+  <target name="rename-gs2build-files-unix" if="collection.building.enabled.unix">
+    <property name="gs2build-extra.home" value="${gs2build.home}/gs2build-extra"/>
+    <copy file="${gs2build-extra.home}/configure" tofile="${gs2build.home}/configure"/>    
+    <chmod file="${gs2build.home}/configure" perm="a+x"/>
+    <copy file="${gs2build-extra.home}/configure.in" tofile="${gs2build.home}/configure.in"/>
+    <copy file="${gs2build-extra.home}/Makefile.in" tofile="${gs2build.home}/Makefile.in"/>  
+    <copy file="${gs2build-extra.home}/packages.configure" tofile="${gs2build.home}/packages/configure"/>
+    <chmod file="${gs2build.home}/packages/configure" perm="a+x"/>
+    <copy file="${gs2build-extra.home}/packages.Makefile.in" tofile="${gs2build.home}/packages/Makefile.in"/>
+    <copy file="${gs2build-extra.home}/lib.Makefile.in" tofile="${gs2build.home}/lib/Makefile.in"/>  
+  </target>
+  
+  <target name="prepare-gli" depends="init" if="collection.building.enabled" unless="gli.present">
+    <antcall target="checkout-gli"/>
+  </target>
+  
+  <target name="checkout-gli" depends="check-cvsroot,init" if="collection.building.enabled" unless="nocvs.mode">
+    <echo>checking out gli</echo>
+    <cvs command="checkout -P" package="gli"/>
+  </target>
+    
+  <target name="configure-gs2building" depends="init" if="collection.building.enabled"
+    description="Configure only the Greenstone 2 building components">
+    <exec executable="${gs2build.home}/configure" os="${os.linux},${os.solaris}"
+      dir="${gs2build.home}">
+      <arg value="--prefix=${gs2build.home}"/>
+    </exec>
+    <exec executable="${gs2build.home}/configure" os="${os.mac}"
+      dir="${gs2build.home}">
+      <arg value="--prefix=${gs2build.home}"/>
+      <arg value="--with-gdbm=${gdbm.installed.path}"/>
+    </exec>
+  </target>
+
+  <target name="clean-gs2building" depends="init,clean-gli,clean-gs2build" 
+    description="Clean only the Greenstone 2 building components" 
+    if="collection.building.enabled"/>
+  
+  <target name="clean-gli" depends="init" if="collection.building.enabled">
+    <!-- gli -->
+    <property name="gli.home" value="${basedir}/gli"/>
+    <!-- linux -->
+    <exec executable="clean.sh" os="${os.unix}" dir="${gli.home}"
+      resolveExecutable="true"/>
+    <!-- windows -->
+    <exec executable="clean.bat" os="${os.windows}" dir="${gli.home}"
+      resolveExecutable="true"/>
+  </target>
+  
+  <target name="clean-gs2build" depends="init" if="collection.building.enabled">
+    <!-- gs2build -->
+    <!--linux:  -->
+    <exec executable="make" os="${os.unix}" dir="${gs2build.home}">
+      <arg value="clean"/>
+    </exec>
+    <!-- windows: -->    
+    <!-- run the setup script -->
+    <exec executable="${compile.windows.c++.setup}"/>
+    <exec executable="nmake" dir="${gs2build.home}">
+     <arg value="/f"/>
+     <arg value="win32.mak"/>
+     <arg value="clean"/>
+    </exec>
+  </target>
+  
+  <target name="distclean-gs2build" depends="init" if="collection.building.enabled">
+    <!-- gs2build -->
+    <!--linux:  -->
+    <exec executable="make" os="${os.unix}" dir="${gs2build.home}">
+      <arg value="distclean"/>
+    </exec>
+    <!-- windows: -->    
+  </target>
+  
+  <target name="compile-gs2building" depends="init,compile-gs2build,compile-gli" if="collection.building.enabled"
+    description="Compile only the Greenstone 2 building components">
+  </target>
+  
+  <target name="compile-gli" depends="init" if="collection.building.enabled">
+    <!-- gli -->
+    <property name="gli.home" value="${basedir}/gli"/>
+    <!-- linux -->
+    <exec executable="makegli.sh" os="${os.unix}" dir="${gli.home}"
+      resolveExecutable="true"/>
+    <!-- windows -->
+    <exec executable="makegli.bat" os="${os.windows}" dir="${gli.home}"
+      resolveExecutable="true"/>
+  </target>
+  
+  <target name="compile-gs2build" depends="init" if="collection.building.enabled">
+    <!-- gs2build -->
+    <!--linux: make, make install -->
+    <exec executable="make" os="${os.unix}" dir="${gs2build.home}">
+    </exec>
+    <exec executable="make" os="${os.unix}" dir="${gs2build.home}">
+      <arg value="install"/>
+    </exec>
+    <!-- run the setup script -->
+    <exec executable="${compile.windows.c++.setup}" os="${os.windows}"/>
+    <exec executable="nmake" dir="${gs2build.home}" os="${os.windows}">
+     <arg value="/f"/>
+     <arg value="win32.mak"/>
+    </exec>
+    <exec executable="nmake" dir="${gs2build.home}" os="${os.windows}">
+     <arg value="/f"/>
+     <arg value="win32.mak"/>
+     <arg value="install"/>
+    </exec>
+    <!-- LuceneWrapper jar file not installed by default -->
+    <mkdir dir="${gs2build.home}/bin/java"/>
+    <copy file="${lucene.home}/LuceneWrapper.jar" todir="${gs2build.home}/bin/java"/>
+    <antcall target="install-gs2build-indexers-windows"/>
+    <antcall target="install-macos-extra"/>
+  </target>
+  
+  <target name="install-gs2build-indexers-windows" depends="init" if="collection.building.enabled.windows">
+    <copy todir="${gs2build.home}/bin/windows">
+      <fileset dir="${gs2build.home}/indexers/bin">
+	<include name="*.*"/>
+      </fileset>
+    </copy>
+  </target>
+
+  <target name="gli" description="Run the Greenstone Librarian Interface" depends="init" if="collection.building.enabled">
+    <exec executable="${basedir}/gli/gli4gs3.sh" os="${os.linux},${os.solaris}" dir="${basedir}/gli" spawn="true">
+      <env key="gsdl3path" path="${basedir}"/>
+      <env key="gsdlpath" path="${basedir}/gs2build"/>
+    </exec>
+    <exec executable="${basedir}/gli/gli4gs3.sh" os="${os.mac}" dir="${basedir}/gli" spawn="true">
+      <env key="gsdl3path" path="${basedir}"/>
+      <env key="gsdlpath" path="${basedir}/gs2build"/>
+      <env key="DYLD_LIBRARY_PATH" path="${env.DYLD_LIBRARY_PATH}:${gdbm.installed.path}/lib"/>
+    </exec>
+    <exec executable="${basedir}/gli/gli4gs3.bat" os="${os.windows}" dir="${basedir}/gli" spawn="true">
+      <env key="GSDL3PATH" path="${basedir}"/>
+      <env key="GSDLPATH" path="${basedir}/gs2build"/>
+    </exec>
+    <echo>Running GLI from Ant means that you don't get to see any of the terminal output. If you have problems with GLI and want to see the output, please run the script gli4gs3.sh/bat from the greenstone3/gli directory.
+    </echo>
+  </target>
+ 
+
+<!-- ======================== TESTING Targets ========================= -->
+  
+  <target name="test" description="Run the (incomplete) JUnit test suite "
+    depends="init">
+    <mkdir dir="${basedir}/test"/>
+    <junit printsummary="withOutAndErr"
+      errorproperty="test.failed"
+      failureproperty="test.failed"
+      fork="${junit.fork}">
+      <formatter type="plain"/>
+      <classpath>
+	<pathelement location="${build.home}/gsdl3test.jar"/>
+	<path refid="compile.classpath"/>
+      </classpath>
+      <test name="${testcase}" if="testcase"/>
+      <batchtest todir="${basedir}/test" unless="testcase">
+	<fileset dir="${build.home}"
+	  includes="**/*Test.class"
+	  />
+      </batchtest>
+    </junit>
+    <echo>
+      *********************************************
+       Test output can be found in directory 'test'
+      *********************************************
+    </echo>
+  </target>
+
+</project>
+
+
Index: /greenstone3/trunk/dist-resources/convert-build-xml-source.xsl
===================================================================
--- /greenstone3/trunk/dist-resources/convert-build-xml-source.xsl	(revision 14125)
+++ /greenstone3/trunk/dist-resources/convert-build-xml-source.xsl	(revision 14125)
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+ <!-- we basically want to copy everything except for a few targets that no longer apply -->
+  <xsl:output method="xml"/>
+
+  <!-- for some reason, the default copy-of doesn't copy empty attributes, so have this to get the empty arg1 in equals-->
+  <xsl:template match="project|condition|and|isset|equals|not|or">
+    <xsl:copy>
+      <xsl:copy-of select="@*"/>
+      <xsl:apply-templates/>
+    </xsl:copy>
+  </xsl:template>
+      
+  <!-- delete the unnecessary targets -->
+  <xsl:template match="target[starts-with(@name, 'prepare')]"></xsl:template>
+  <xsl:template match="target[starts-with(@name, 'cvsupdate')]"></xsl:template>
+  <xsl:template match="target[starts-with(@name, 'update')]"></xsl:template>
+  <xsl:template match="target[starts-with(@name, 'checkout')]"></xsl:template>
+  <xsl:template match="target[starts-with(@name, 'rename-gs2build')]"></xsl:template>
+  <xsl:template match="target[@name='test']"></xsl:template>
+  <xsl:template match="target[@name='get-macos-extra']"></xsl:template>
+  <xsl:template match="target[@name='get-windows-binaries']"></xsl:template>
+  
+  <xsl:template match="property[@name='install-command']">
+    <property name="install-command" value="ant [options] install"/>
+  </xsl:template>
+
+  <xsl:variable name="install-for-dist" select="document('dist-build.xml')/project/target[@name='install-for-source-dist']"/>
+  
+  <!-- copy in our new install target -->
+  <xsl:template match="target[@name='install']">
+    <target name="install">
+      <xsl:copy-of select="$install-for-dist/@depends|$install-for-dist/@description|$install-for-dist/@if|$install-for-dist/@unless|$install-for-dist/node()"/>
+    </target>
+  </xsl:template>
+
+  <xsl:template match="*">
+    <xsl:copy-of select="."/>
+  </xsl:template>
+
+  <xsl:template match="comment()">
+    <xsl:copy-of select="."/>
+    <xsl:text>
+</xsl:text>
+  </xsl:template>
+    
+</xsl:stylesheet>
Index: /greenstone3/trunk/dist-resources/convert-build-xml.xsl
===================================================================
--- /greenstone3/trunk/dist-resources/convert-build-xml.xsl	(revision 14125)
+++ /greenstone3/trunk/dist-resources/convert-build-xml.xsl	(revision 14125)
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+ <!-- we basically want to copy everything except for a few targets that no longer apply -->
+  <xsl:output method="xml"/>
+
+  <!-- for some reason, the default copy-of doesn't copy empty attributes, so have this to get the empty arg1 in equals-->
+  <xsl:template match="project|condition|and|isset|equals|not|or">
+    <xsl:copy>
+      <xsl:copy-of select="@*"/>
+      <xsl:apply-templates/>
+    </xsl:copy>
+  </xsl:template>
+  
+  <!-- delete the old install target-->
+  <xsl:template match="target[@name='install']"></xsl:template>
+
+  <!-- delete the unnecessary targets -->
+  <xsl:template match="target[starts-with(@name, 'prepare')]"></xsl:template>
+  <xsl:template match="target[starts-with(@name, 'cvsupdate')]"></xsl:template>
+  <xsl:template match="target[starts-with(@name, 'update')]"></xsl:template>
+  <xsl:template match="target[starts-with(@name, 'checkout')]"></xsl:template>
+  <xsl:template match="target[starts-with(@name, 'rename-gs2build')]"></xsl:template>
+  <xsl:template match="target[@name='test']"></xsl:template>
+  <xsl:template match="target[@name='get-macos-extra']"></xsl:template>
+  <xsl:template match="target[@name='get-windows-binaries']"></xsl:template>
+
+  <xsl:variable name="usage-for-dist" select="document('dist-build.xml')/project/target[@name='usage-for-binary-dist']"/>
+  
+  <!-- copy in our new usage target -->
+  <xsl:template match="target[@name='usage']">
+    <target name="usage">
+      <xsl:copy-of select="$usage-for-dist/@description|$usage-for-dist/node()"/>
+    </target>
+  </xsl:template>
+  
+  <xsl:template match="*">
+    <xsl:copy-of select="."/>
+  </xsl:template>
+
+  <xsl:template match="comment()">
+    <xsl:copy-of select="."/>
+    <xsl:text>
+</xsl:text>
+  </xsl:template>
+    
+</xsl:stylesheet>
Index: /greenstone3/trunk/dist-resources/dist-build.xml
===================================================================
--- /greenstone3/trunk/dist-resources/dist-build.xml	(revision 14125)
+++ /greenstone3/trunk/dist-resources/dist-build.xml	(revision 14125)
@@ -0,0 +1,406 @@
+<?xml version="1.0"?>
+
+<!-- ====================================================================== 
+     March 2005                                                    
+
+     Greenstone3 build and install script
+                   
+     kjdon                                                                
+     ====================================================================== -->
+<project name="greenstone3-distribution" default="usage" basedir="..">
+  
+  <!-- include standard build file -->
+  <import file="../build.xml"/>
+  
+  <property name="documented.collections.home" value="/home/nzdl/for-distributions/collect"/>
+  <property name="greenstone3-change-date" value="Tue Feb 20 12:13:42 NZDT 2007"/>
+  <property name="gs2build-change-date" value="Wed Dec 13 10:35:57 NZDT 2006"/>
+
+  <!-- ====================== DISTRIBUTION Targets ========================= -->
+  
+  <!-- these two, do we need tomcat and axis for compilation??-->
+  <!-- Create the binaries for windows distribution -->
+  <target name="prepare-windows" depends="init">
+    <cvs command="checkout -P" package="gs2build" /> 
+    <antcall target="unzip-windows-packages"/>
+    <antcall target="checkout-winbin"/>
+    <antcall target="get-perl-for-windows"/>
+  </target>
+  
+  <target name="build-windows" depends="init">
+    <antcall target="cvsupdate-distribution"/>
+    <cvs command="update -dP" package="winbin" />
+    <antcall target="get-windows-binaries"/>
+    <antcall target="rename-gs2build-files-windows"/>
+    <antcall target="compile-gs2build"/>
+    <antcall target="compile-packages"/>
+   </target>
+  
+  <!-- Create the binaries for Unix/Mac distributions -->
+  <target name="prepare-unix" depends="init">
+    <cvs command="checkout -P" package="gs2build"/>
+    <cvs command="checkout -P" packages="gli"/>
+  </target>
+
+  <target name="update-unix" depends="init">
+    <antcall target="cvsupdate-distribution"/>
+    <antcall target="rename-gs2build-files-unix"/>
+    <antcall target="delete-windows-files"/>
+  </target>
+  
+  <target name="configure-unix" depends="init">
+    <antcall target="configure-c++"/>
+  </target>    
+  <target name="build-unix" depends="init">
+    <antcall target="compile-packages"/>
+    <antcall target="compile-gs2build"/>
+  </target>
+    
+  <!-- creates the base distribution. Needs binaries copied in to it from other
+    greenstones (prepare-os targets) -->
+  <target name="create-distribution-1" depends="init" description="do all the initial downloading and setting up">
+    <cvs command="export -D '1 second ago'" package="gs2build"/>
+    <cvs command="export -D '1 second ago'" package="gli"/>
+    <delete file="${gli.home}/gli.bat"/>
+    <delete file="${gli.home}/gli.sh"/>
+    <delete file="${gli.home}/gems.bat"/>
+    <delete file="${gli.home}/gems.sh"/>
+    <antcall target="rename-gs2build-files-dist"/>    
+    <delete dir="${gs2build-extra.home}"/>
+    
+    <!--<antcall target="unzip-windows-packages"/> do we need this?-->
+    <antcall target="prepare-tomcat"/>
+    <delete file="${packages.home}/apache-tomcat-5.5.12.zip"/>
+    <delete file="${packages.home}/apache-tomcat-5.5.12-compat.zip"/>
+    <antcall target="prepare-axis"/>
+    <delete file="${packages.home}/axis-bin-1_2_1.zip"/>
+    <!-- delete old axis dir -->
+    <delete dir="${packages.home}/axis"/>
+    <mkdir dir="${web.home}/applet"/>
+    <mkdir dir="${web.home}/logs"/>
+    <antcall target="prepare-ant"/>
+    <delete file="${packages.home}/apache-ant-1.7.0-bin.zip"/>
+    <antcall target="prepare-collections"/>
+
+    <!-- get good XML-Parser - does this work? -->
+    <antcall target="get-xml-parser"/>
+    <!-- documented collections -->
+    <antcall target="get-documented-collections"/>
+
+    <delete file="${basedir}/README-CVS.txt"/>
+    <delete file="${basedir}/TODO.txt"/>
+
+    <!-- make the extra directories needed for a release -->
+    <mkdir dir="${basedir}/Linux/lib/jni"/>
+    <mkdir dir="${basedir}/Darwin/lib/jni"/>
+    <mkdir dir="${basedir}/Windows/lib/jni"/>
+    <mkdir dir="${gs2build.home}/Unix/bin/linux"/>
+    <mkdir dir="${gs2build.home}/Unix/bin/darwin"/>
+    <mkdir dir="${gs2build.home}/Windows/bin/windows"/>
+    <mkdir dir="${gs2build.home}/source/Windows"/>
+    <mkdir dir="${gs2build.home}/source/Unix"/>
+
+  </target>
+
+  <target name="create-distribution-2" description="do all the compilation">
+    <!-- compile the java stuff -->
+    <antcall target="compile-web"/>
+    <antcall target="configure-packages-and-indexers"/>
+    <antcall target="compile-packages-and-indexers-javaonly"/>
+    <antcall target="distclean-packages"/>
+    <antcall target="compile-core"/>
+    <antcall target="compile-gli"/>
+  </target>
+
+  <target name="create-distribution-3" depends="init" description="Do the rearranging of source code etc">
+
+    <!-- move top-level os dependent files -->
+    <copy todir="${basedir}/Linux">
+      <fileset dir="${basedir}">
+	<include name="*.sh"/>
+      </fileset>
+    </copy>
+    <chmod dir="${basedir}/Linux" perm="ugo+rx" 
+      includes="*.sh"/>
+    <move todir="${basedir}/Darwin">
+      <fileset dir="${basedir}">
+	<include name="*.sh"/>
+      </fileset>
+    </move>
+    <chmod dir="${basedir}/Darwin" perm="ugo+rx" 
+      includes="*.sh"/>
+    <move todir="${basedir}/Windows">
+      <fileset dir="${basedir}">
+	<include name="*.bat"/>
+      </fileset>
+    </move>
+
+    <!-- rearrange collection building stuff -->
+    <move file="${gs2build.home}/win32.mak" tofile="${gs2build.home}/source/Windows/win32.mak"/>
+    <move file="${gs2build.home}/setup.bat" tofile="${gs2build.home}/source/Windows/setup.bat"/>
+    <move file="${gs2build.home}/WIN32cfg.h" tofile="${gs2build.home}/source/Windows/WIN32cfg.h"/>
+    <move todir="${gs2build.home}/source/Unix/">
+      <fileset dir="${gs2build.home}">
+	<include name="config*"/>
+	<include name="ac*"/>
+	<include name="install-sh"/>
+	<include name="setup.bash"/>
+	<include name="Makefile.in"/>
+      </fileset>
+    </move>
+    <!-- general source files -->
+    <move todir="${gs2build.home}/source/src" failonerror="false">
+      <fileset dir="${gs2build.home}/src" defaultexcludes="no"/>
+    </move>
+    <move todir="${gs2build.home}/source/lib" failonerror="false">
+      <fileset dir="${gs2build.home}/lib" defaultexcludes="no"/>
+    </move>
+    <move todir="${gs2build.home}/source/packages" failonerror="false">
+      <fileset dir="${gs2build.home}/packages" defaultexcludes="no"/>
+    </move>
+    <move todir="${gs2build.home}/source/indexers" failonerror="false">
+      <fileset dir="${gs2build.home}/indexers" defaultexcludes="no"/>
+    </move>
+
+    <!-- generate modified build.xml file -->
+    <antcall target="run-xslt-binary"/>
+
+    <!-- clean up -->
+    <delete dir="${basedir}/build"/>
+    <delete dir="${basedir}/lib/jni"/>
+  </target>
+  
+
+  <target name="create-source-distribution" depends="init">
+    <cvs command="export -D '1 second ago'" package="gs2build"/>
+    <cvs command="export -D '1 second ago'" package="gli"/>
+    <delete file="${gli.home}/gli.bat"/>
+    <delete file="${gli.home}/gli.sh"/>
+    <antcall target="rename-gs2build-files-dist"/>
+    <delete dir="${gs2build-extra.home}"/>
+    <antcall target="prepare-tomcat"/>
+    <delete file="${packages.home}/apache-tomcat-5.5.12.zip"/>
+    <delete file="${packages.home}/apache-tomcat-5.5.12-compat.zip"/>
+    <antcall target="prepare-ant"/>
+    <delete file="${packages.home}/apache-ant-1.7.0-bin.zip"/>
+    <antcall target="prepare-collections"/>
+    <antcall target="prepare-axis"/>
+    <delete file="${packages.home}/axis-bin-1_2_1.zip"/>
+    <!-- delete old axis dir -->
+    <delete dir="${packages.home}/axis"/>
+    <mkdir dir="${web.home}/applet"/>
+    <mkdir dir="${web.home}/logs"/>
+
+    <!-- download the mac XML parser just in case: it will only be unpacked if on a mac  -->
+    <get src="http://www.greenstone.org/gs3files/XML-Parser.tar.gz"
+      dest="${gs2build.home}/perllib/cpan/XML-Parser.tar.gz"
+      usetimestamp="true"/>
+
+    <!-- generate modified build.xml file -->
+    <antcall target="run-xslt-source"/>
+    <!--<delete dir="${basedir}/dist-resources"/>-->
+
+  </target>
+
+  <!-- Supplementary targets -->
+
+  <target name="cvsupdate-distribution" depends="init">
+    <antcall target="cvsupdate-packages"/>
+    <antcall target="cvsupdate-core"/>
+    <antcall target="cvsupdate-gs2build"/>
+    <antcall target="cvsupdate-web"/>
+  </target>
+
+  <target name="run-xslt-source" depends="init">
+    <xslt in="${basedir}/build.xml" out="${basedir}/dist-build.xml" style="${basedir}/dist-resources/convert-build-xml-source.xsl"/>
+  </target>
+  
+  <target name="run-xslt-binary" depends="init">
+    <xslt in="${basedir}/build.xml" out="${basedir}/dist-build.xml" style="${basedir}/dist-resources/convert-build-xml.xsl"/>
+  </target>
+  
+  <target name="rename-gs2build-files-dist" depends="init,rename-gs2build-files-unix">
+    <copy file="${gs2build-extra.home}/lib.win32.mak" tofile="${gs2build.home}/lib/win32.mak"/>
+   <copy file="${gs2build-extra.home}/win32.mak" tofile="${gs2build.home}/win32.mak"/>
+   <copy file="${gs2build-extra.home}/setup.bat" tofile="${gs2build.home}/setup.bat"/>
+  </target>   
+
+  <target name="configure-packages-and-indexers" depends="init">
+    <exec executable="${indexers.home}/configure"
+      dir="${indexers.home}">
+      <arg value="--prefix=${basedir}"/>
+      <arg value="--libdir=${lib.jni}"/>
+    </exec>          
+    <exec executable="${javagdbm.home}/configure"
+      dir="${javagdbm.home}">
+      <arg value="--prefix=${basedir}"/>
+      <arg value="--libdir=${lib.jni}"/>
+    </exec>    
+
+  </target>
+  <target name="compile-packages-and-indexers-javaonly" depends="init">
+    <echo>Compiling Indexers</echo>
+    <exec executable="make" os="${os.unix}"
+       dir="${indexers.home}">
+      <arg value="javaonly"/>
+    </exec>
+    <exec executable="make" os="${os.unix}"
+      dir="${indexers.home}">
+      <arg value="install-javaonly"/>
+    </exec>
+    <!-- install the jar files -->
+    <copy file="${mg.home}/mg.jar" todir="${lib.jni}"/>
+    <copy file="${mgpp.home}/mgpp.jar" todir="${lib.jni}"/>
+    <copy file="${lucene.home}/LuceneWrapper.jar" todir="${web.lib}"/>
+    
+    <!-- javagdbm -->
+    <exec executable="make" os="${os.unix}"
+      dir="${javagdbm.home}">
+      <arg value="javaonly"/>
+    </exec>
+    <exec executable="make" os="${os.unix}"
+      dir="${javagdbm.home}">
+      <arg value="installjava"/>
+    </exec>
+    <!-- install the jar file -->
+    <copy file="${javagdbm.home}/javagdbm.jar" todir="${lib.jni}"/>
+
+  </target>
+
+  <target name="delete-windows-files" depends="init" unless="current.os.iswindows">
+    <delete dir="${basedir}/winutil"/>
+    <delete>
+      <fileset dir="${lib.jni}" includes="*.dll"/>
+    </delete>
+  </target>
+
+  <target name="get-perl-for-windows" depends="init" if="current.os.iswindows">
+    <mkdir dir="${gs2build.home}/bin/windows"/>
+    <get src="http://www.greenstone.org/gs3files/perl-for-windows.zip"
+      dest="${gs2build.home}/bin/windows/perl-for-windows.zip"
+      usetimestamp="true"/>
+    <unzip src="${gs2build.home}/bin/windows/perl-for-windows.zip" 
+      dest="${gs2build.home}/bin/windows"/>
+    <delete file="${gs2build.home}/bin/windows/perl-for-windows.zip"/>
+  </target>
+
+  <target name="distclean-packages" depends="init">
+    <!-- indexers : just call the make target -->
+    <exec executable="make" os="${os.unix}"
+      dir="${indexers.home}">
+      <arg value="distclean"/>
+    </exec>
+    <!-- javagdbm -->
+    <exec executable="make" os="${os.unix}"
+      dir="${javagdbm.home}">
+      <arg value="distclean"/>
+    </exec>
+  </target>
+
+  <!-- copy the doc eg colls from /home/nzdl - note we don't include the formatting ones -->
+  <target name="get-documented-collections" depends="init">
+    <property name="collect.home" value="${basedir}/web/sites/localsite/collect"/>
+    <copy todir="${collect.home}/MARC-e">
+      <fileset dir="${documented.collections.home}/MARC-e"/>
+    </copy>
+    <copy todir="${collect.home}/cltbib-e">
+      <fileset dir="${documented.collections.home}/cltbib-e"/>
+    </copy>
+    <copy todir="${collect.home}/dls-e">
+      <fileset dir="${documented.collections.home}/dls-e"/>
+    </copy>
+    <copy todir="${collect.home}/dspace-e">
+      <fileset dir="${documented.collections.home}/dspace-e"/>
+    </copy>
+    <copy todir="${collect.home}/gsarch-e">
+      <fileset dir="${documented.collections.home}/gsarch-e"/>
+    </copy>
+    <copy todir="${collect.home}/image-e">
+      <fileset dir="${documented.collections.home}/image-e"/>
+    </copy>
+    <copy todir="${collect.home}/isis-e">
+      <fileset dir="${documented.collections.home}/isis-e"/>
+    </copy>
+    <copy todir="${collect.home}/oai-e">
+      <fileset dir="${documented.collections.home}/oai-e"/>
+    </copy>
+    <copy todir="${collect.home}/pagedimg-e">
+      <fileset dir="${documented.collections.home}/pagedimg-e"/>
+    </copy>
+    <copy todir="${collect.home}/wrdpdf-e">
+      <fileset dir="${documented.collections.home}/wrdpdf-e"/>
+    </copy>
+  </target>
+
+  <target name="get-xml-parser" depends="init">
+    <get src="http://www.greenstone.org/gs3files/XML-Parser.tar.gz"
+      dest="${gs2build.home}/perllib/cpan/XML-Parser.tar.gz"
+      usetimestamp="true"/>
+    <untar src="${gs2build.home}/perllib/cpan/XML-Parser.tar.gz"
+      dest="${gs2build.home}/perllib/cpan/"
+      compression="gzip"/>
+    <delete file="${gs2build.home}/perllib/cpan/XML-Parser.tar.gz"/>
+  </target>
+
+  <target name="create-changelog">
+    <!-- generate greenstone 3 changelog -->
+    <exec executable="/home/nzdl/for-distributions/bin/script/cvs2cl.pl"
+      dir="${basedir}">
+      <arg value="-P"/>
+      <arg value="-F"/>
+      <arg value="trunk"/>
+      <arg value="-r"/>
+      <arg value="-S"/>
+      <arg value="-l"/>
+      <arg value="-d'${greenstone3-change-date}&lt;tomorrow'"/>
+      <arg value="-f"/>
+      <arg value="greenstone-${app.version}-ChangeLog.txt"/>
+      <arg value="-I"/>
+      <arg value="gli/.*|gs2build/.*"/>
+    </exec> 
+    <!-- generate coll building change log -->
+    <exec executable="/home/nzdl/for-distributions/bin/script/cvs2cl.pl"
+      dir="${basedir}">
+      <arg value="-P"/>
+      <arg value="-F"/>
+      <arg value="trunk"/>
+      <arg value="-r"/>
+      <arg value="-S"/>
+      <arg value="-l"/>
+      <arg value="-d'${gs2build-change-date}&lt;tomorrow'"/>
+      <arg value="-f"/>
+      <arg value="greenstone-${app.version}-ChangeLog-collbuilding.txt"/>
+      <arg value="gli"/>
+      <arg value="gs2build"/>
+    </exec> 
+  </target>
+  <!-- new targets to go in distribution build.xml files -->
+
+  <!-- new usage target for binary release -->
+  <target name="usage-for-binary-dist" description="Print a help message">
+    <echo message="  Execute 'ant -projecthelp' for a list of targets."/>
+    <echo message="  Execute 'ant -help' for Ant help."/>
+  </target>
+    
+
+  <!-- new install target for source distribution -->
+  <target name="install-for-source-dist" depends="init" description="install the source distribution. Includes configuring and compiling">
+    <antcall target="unzip-windows-packages"/>
+    <!-- do the java version dependent stuff -->
+    <antcall target="configure-java-version"/>
+    <antcall target="install-macos-extra"/>
+    <!-- set gsdlhome in setup.bat -->
+    <antcall target="gs2build-edit-setup-bat"/>
+    <antcall target="install-indexer-files"/>
+    <antcall target="configure"/>
+    <antcall target="configure-c++"/>
+    <antcall target="compile"/>
+    <!-- make sure we have execute permission for the .sh files -->
+    <chmod dir="${basedir}" perm="ugo+rx" 
+      includes="*.sh"/>
+
+  </target>
+
+</project>
+  
+
Index: /greenstone3/trunk/dist-resources/tomcat-server.xsl
===================================================================
--- /greenstone3/trunk/dist-resources/tomcat-server.xsl	(revision 14125)
+++ /greenstone3/trunk/dist-resources/tomcat-server.xsl	(revision 14125)
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+ <!-- we basically want to copy everything, but add in a few bits for gs3 -->
+  <xsl:output method="xml"/>
+  
+  <xsl:template match="Server">
+    <xsl:copy>
+      <xsl:copy-of select="@*"/>
+      <xsl:apply-templates/>
+    </xsl:copy>
+    <xsl:text>
+    </xsl:text>
+  </xsl:template>
+  
+  <xsl:template match="Service | Engine ">
+    <xsl:copy>
+      <xsl:copy-of select="@*"/>
+      <xsl:apply-templates/>
+    </xsl:copy>
+  </xsl:template>
+  
+  <xsl:template match="Connector[@port='8080']">
+    <xsl:copy>
+    <xsl:for-each select="@*">
+      <xsl:choose>
+	<xsl:when test="name()='port'">
+	  <xsl:attribute name="port">@port@</xsl:attribute>
+	</xsl:when>
+	<xsl:otherwise>
+	  <xsl:copy-of select="."/>
+	</xsl:otherwise>
+      </xsl:choose>
+    </xsl:for-each>
+      <xsl:apply-templates/>
+    </xsl:copy>
+  </xsl:template>
+	  
+  <xsl:template match="Host">
+    <xsl:copy>
+      <xsl:copy-of select="@*"/>
+      <xsl:apply-templates/>
+      <Context path="/gsdl3" docBase="@gsdl3home@/web" debug="1" 
+	reloadable="true">
+	<Resources allowLinking='true'/>
+      </Context>
+    </xsl:copy>
+  </xsl:template>
+      
+  <xsl:template match="*">
+    <xsl:copy-of select="."/>
+  </xsl:template>
+
+  <xsl:template match="comment()">
+    <xsl:copy-of select="."/>
+    <xsl:text>
+</xsl:text>
+  </xsl:template>
+    
+</xsl:stylesheet>
Index: /greenstone3/trunk/docs/Makefile.in
===================================================================
--- /greenstone3/trunk/docs/Makefile.in	(revision 14125)
+++ /greenstone3/trunk/docs/Makefile.in	(revision 14125)
@@ -0,0 +1,42 @@
+###########################################################################
+#
+# Makefile -- Makefile for documentation included with Greenstone
+#
+# 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 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.
+#
+###########################################################################
+
+GSDL3HOME=..
+
+JAVADOC=$(JAVA_HOME)/bin/javadoc
+JAVADOCDIR=$(GSDL3HOME)/docs/javadoc
+SRCDIR=$(GSDL3HOME)/src/java
+PACKAGEDIR=$(GSDL3HOME)/packages
+
+docs:
+	$(JAVADOC) -d $(JAVADOCDIR) -private -link http://java.sun.com/j2se/1.4.2/docs/api/ `find $(SRCDIR) -name '*.java'` `find $(PACKAGEDIR) -name '*.java'` > $(JAVADOCDIR)/javadoc_log
+
+# what about the CVS dir??
+clean:
+	rm -rf $(JAVADOCDIR)/*
+
+distclean: clean
+	rm -f Makefile
Index: /greenstone3/trunk/docs/javadoc/.keepme
===================================================================
--- /greenstone3/trunk/docs/javadoc/.keepme	(revision 14125)
+++ /greenstone3/trunk/docs/javadoc/.keepme	(revision 14125)
@@ -0,0 +1,1 @@
+a file to ensure cvs keeps the directory
Index: /greenstone3/trunk/docs/manual/hints.tex
===================================================================
--- /greenstone3/trunk/docs/manual/hints.tex	(revision 14125)
+++ /greenstone3/trunk/docs/manual/hints.tex	(revision 14125)
@@ -0,0 +1,228 @@
+\documentclass[a4paper,11pt]{article}
+\usepackage{times,epsfig}
+
+\newenvironment{bulletedlist}%
+{\begin{list}{$\bullet$}{\setlength{\itemsep}{0pt}\setlength{\parsep}{0pt}}}%
+{\end{list}}
+
+
+\begin{document}
+
+\title{Some hints for developers}
+
+\maketitle
+
+\section{Java code}
+
+the java code is found in gsdl3/src/java/org/greenstone/gsdl3
+util has various utility classes, service has the services, action has the actions, build has the building code, etc.
+
+\section{Working with XML}
+
+We use the DOM model for handling XML. This involves Documents, Nodes, Elements etc. Node is the basic thing in the tree, all others inherit from this. A Document represents a whole document, and is a kind of container for all the nodes. Elements and Nodes are not supposed to exist outside of the context of a document, so you have to have a document to create them. The document is not the top level node in the tree, to get this, use Document.getDocumentElement(). If you create nodes etc but dont append them to something already in the document tree, they will be separate - but they still know who their owner document is.
+
+There is a utility class called XMLConverter - this creates new Documents, and converts Strings or files to Documents.
+eg:
+XMLConverter converter = new XMLConverter();
+Document doc = converter.newDOM();
+
+File stylesheet = new File(``query.xsl'');
+Document style = converter.getDOM(stylesheet);
+
+String message = ``<message><request type='cgi'/></message>'';
+Document m = converter.getDOM(message);
+
+To output a document as a String, use converter.getString(doc);
+
+
+To add nodes and stuff to an empty document - create them, then append to the tree
+
+Document doc = converter.newDOM();
+Element e = doc.createElement(``message'');
+doc.appendChild(e);
+
+Note, you can only append one node to a document - this will become the toplevel node. After that, you can append nodes to child nodes as you like, but a document is only allowed one top level node.
+
+DOM006 Hierarchy request error: happens if you have more than one root node in your document
+
+\section{Working with XSLT}
+
+* adding html to an xml doc:
+
+eg I have a text node with html inside it inside a resource element
+to add that to a new XML doc, I use
+{\em <xsl:value-of select='resource'>\/}
+
+if the output mode is xml or html, this will escape any special characters
+ie $<$ and $>$ etc
+
+use
+{\em <xsl:value-of disable-output-escaping="yes" select='resource'>\/}
+instead.
+
+* including an xml doc into a stylesheet:
+
+{\em <xsl:variable name='import' select='document(``newdoc.xml'')'/>\/}
+
+then can use the info:
+
+{\em <xsl:value-of select='\$import/element'/>\/}
+
+* selecting an ancestor:
+
+ the ancestor axis contains the parent of the context node, and its
+ parent and so on. to pick one node among these:
+ ancestor::elem-name. I dont know how this works if there are two
+ nodes with the same name in the axis.
+
+* basic XSLT elements
+\begin{quote}\begin{footnotesize}\begin{verbatim}
+<xsl:template match='xxx' name='yyy'/>
+
+<xsl:apply-templates select='xxx'/>
+<xsl:call-templates name='yyy'/>
+
+<xsl:variable name='doc' select='document("layout.xml")'/>
+
+<xsl:value-of select='$doc/chapter1'/> $
+\end{verbatim}\end{footnotesize}\end{quote}
+
+* using namespaces
+If you are using the same namespace in more than one file, eg in the source xml and in the stylesheet, make sure that the URI for the xmlns:xxx thingy is the same in both cases---otherwise the names dont match. This includes http:// on the front.
+
+\subsection{What can I do to speed up XSL transformations?}
+
+This information taken from the Xalan FAQS page.
+
+\begin{bulletedlist}
+
+\item Use a Templates object (with a different Transformers for each
+transformation) to perform multiple transformations with the same set
+of stylesheet instructions (see Multithreading).
+
+\item Set up your stylesheets to function efficiently.
+
+\item Don't use "//" (descendant axes) patterns near the root of a
+large document.
+
+\item Use xsl:key elements and the key() function as an efficient way
+to retrieve node sets.
+
+\item Where possible, use pattern matching rather than xsl:if or
+xsl:when statements.
+
+\item xsl:for-each is fast because it does not require pattern matching.
+
+\item Keep in mind that xsl:sort prevents incremental processing.
+
+\item When you create variables,
+{\em <xsl:variable name="fooElem" select="foo"/>\/} is usually faster
+than \\
+{\em <xsl:variable name="fooElem"><xsl:value-of-select="foo"/></xsl:variable>\/}.
+
+\item Be careful using the last() function.
+
+\item The use of index predicates within match patterns can be expensive.
+
+\item Decoding and encoding is expensive.
+
+\item For the ultimate in server-side scalability, perform transform
+operations on the client. For examples, see appletXMLtoHTML and
+get-todo-list.
+
+\end{bulletedlist}
+
+\section{Java gdbm}
+
+To talk to gdbm, a jni wrapper called java-gdbm is used. It was
+obtained from:\\ {\tt
+http://aurora.rg.iupui.edu/~schadow/dbm-java/pip/gdbm/}
+
+It uses packing objects to convert to and from an array of bytes (in
+gdbm file) from and to java objects. In my GDBMWrapper class I use
+StringPacking - uese UTF-8 encoding. but some stuff came out funny. so
+I had to changes the from\_bytes method in StringPacking.java to use
+new String(raw, "UTF-8") instead of new String(raw). this seems to
+work.
+
+Note---if we use this gdbm stuff to create the file too, may need to
+alter the to-bytes method.
+
+The makefile in j-gdbm is crap---it tries to get stuff from its
+original CVS tree.  I have created a new Makefile---in my-j-gdbm
+directory.  this stuff needs to go into cvs probably.
+
+* I dont think {\em <xsl:with-param name='xxx' select='true'/>\/} is
+the same as {\em <xsl:with-param name='xxx'>true</xsl:with-param>\/}
+use the second one.
+
+
+\section{Resources}
+
+Contents for 'The Java Native Interface Programmer's Guide and
+Specification' on-line\\ {\tt
+http://java.sun.com/docs/books/jni/html/jniTOC.html}
+
+Java Native Interface Specification\\
+{\tt http://java.sun.com/j2se/1.4/docs/guide/jni/spec/jniTOC.doc.html}
+
+JNI Documentation Contents\\
+{\tt http://java.sun.com/j2se/1.4/docs/guide/jni/index.html}
+
+another JNI page\\
+{\tt http://mindprod.com/jni.html}
+
+Java 1.4 api index\\
+{\tt http://java.sun.com/j2se/1.4/docs/api/index.html}
+
+Java tutorial index\\
+{\tt http://java.sun.com/docs/books/tutorial/index.html}
+
+Safari books online - has java, XML, XSLT, etc books\\
+{\tt http://proquest.safaribooksonline.com/mainhom.asp?home}
+
+Java 1.4 i18n FAQ\\
+{\tt http://www.sun.com/developers/gadc/faq/java/java1.4.html}
+
+Java and XSLT page\\
+{\tt http://www.javaolympus.com/java/Java\%20and\%20XSLT.html}
+
+Xalan-Java overview\\
+{\tt http://xml.apache.org/xalan-j/overview.html}
+
+Tomcat documentation index\\
+{\tt http://jakarta.apache.org/tomcat/tomcat-4.0-doc/index.html}
+
+Servlet and JSP tutorial\\
+{\em http://www.apl.jhu.edu/~hall/java/Servlet-Tutorial/\/}
+
+Core Servlets and JavaServer Pages, book by Marty Hall. download the
+pdf from here (try before you buy link)\\ {\tt
+http://www.coreservlets.com/}
+
+J-gdbm page\\
+{\em http://aurora.rg.iupui.edu/~schadow/dbm-java/pip/gdbm/\/}
+
+Stuarts page of links\\
+{\em http://www.cs.waikato.ac.nz/~nzdl/gsdl3/\/}
+
+a good basic xslt tutorial\\
+{\tt http://www.zvon.org/xxl/XSLTutorial/Books/Output/contents.html}
+
+JAXP (java api for xml processing) package overview\\
+{\tt http://java.sun.com/xml/jaxp/dist/1.1/docs/api/overview-summary.html}
+
+DeveloperWorks, xml zone\\
+{\tt http://www-106.ibm.com/developerworks/xml/}
+
+xslt.com\\
+{\tt http://www.xslt.com/}
+
+jeni tennison's xslt pages\\
+{\tt http://www.jenitennison.com/xslt/}
+
+apaches xml tools\\
+{\tt http://xml.apache.org/}
+
+
+\end{document}
Index: /greenstone3/trunk/docs/manual/manual.tex
===================================================================
--- /greenstone3/trunk/docs/manual/manual.tex	(revision 14125)
+++ /greenstone3/trunk/docs/manual/manual.tex	(revision 14125)
@@ -0,0 +1,2400 @@
+\documentclass[a4paper,11pt]{article}
+\usepackage{isolatin1,times,epsfig}
+\hyphenation{Message-Router Text-Query}
+
+\newenvironment{gsc}% Greenstone text bits
+{\begin{footnotesize}\begin{tt}}%
+{\end{tt}\end{footnotesize}}
+ 
+\newcommand{\gst}[1]{{\footnotesize \tt #1}}
+
+\newcommand{\gsii}{Greenstone2}
+\newcommand{\gsiii}{Greenstone3}
+\newcommand{\gs}{Greenstone}
+
+\begin{document}
+
+\title{\gsiii\ : A modular digital library.}
+
+% if you work on this manual, add your name here
+\author{Katherine Don \\[1ex]
+        Department of Computer Science \\
+        University of Waikato \\ Hamilton, New Zealand \\ }
+
+\date{}
+
+\maketitle
+
+\newenvironment{bulletedlist}%
+{\begin{list}{$\bullet$}{\setlength{\itemsep}{0pt}\setlength{\parsep}{0pt}}}%
+{\end{list}}
+
+\noindent
+Greenstone Digital Library Version 3 is a complete redesign and
+reimplementation of the \gs\  digital library software.  The current
+version (\gsii) enjoys considerable success and is being widely used.
+\gsiii \  will capitalize on this success, and in addition it will
+\begin{bulletedlist}
+\item improve flexibility, modularity, and extensibility
+\item lower the bar for ``getting into'' the \gs\  code with a view to
+   understanding and extending it
+\item use XML where possible internally to improve the amount of
+   self-documentation
+\item make full use of existing XML-related standards and software
+\item provide improved internationalization, particularly in terms of sort order,
+   information browsing, etc.
+\item include new features that facilitate additional ``content management''
+   operations
+\item operate on a scale ranging from personal desktop to corporate library
+\item easily permit the incorporation of text mining operations
+\item use Java, to encourage multilinguality, X-compatibility, and to permit
+   easier inclusion of existing Java code (such as for text mining).
+\end{bulletedlist}
+Parts of \gs\  will remain in other languages (e.g. MG, MGPP); JNI (Java
+Native Interface) will be used to communicate with these.
+
+A description of the general design and architecture of \gsiii\  is covered by the document {\em The design of Greenstone3: An agent based dynamic digital library} (design-2002.ps, in the docs/manual directory).
+
+This documentation consists of several parts. Section~\ref{sec:install} is for administrators, and covers \gsiii\  installation, how to access the library, and some administration issues. Section~\ref{sec:user} is for users of the software, and looks at using the sample collections, creating new collections, and how to make small customizations to the interface. The remaining sections are aimed towards  the \gs\  developer. Section~\ref{sec:develop-runtime} describes the run-time system, including the structure of the software, and the message format. Section~\ref{sec:new-features} describes how to add new features to \gs, such as how to add new services, new page types, new plugins for different document formats.  Section~\ref{sec:distributed} describes how to make \gs\  run in a distributed fashion, using SOAP as an example communications protocol. Finally, there are several appendices, including how to install \gs\  from CVS, some notes on Tomcat and SOAP, and a comparison of \gsii\  and \gsiii\  format statements.
+\newpage
+\tableofcontents
+\newpage
+\section{\gs\  installation and administration}\label{sec:install}
+
+This section covers where to get \gsiii\  from, how to install it and how to run it. The standard method of running \gsiii\  is as a Java servlet. We provide the Tomcat servlet container to run the servlet. Standard web servers may  be able to be configured to provide servlet support, and thereby remove the need to use Tomcat. Please see your web server documentation for this. This documentation assumes that you are using Tomcat. To access \gsiii, Tomcat must be started up, and then it can be accessed via a web browser. 
+
+Ant (Java's XML based build tool) is used for compilation, installation and running Greenstone. The \gst{build.xml} file is the configuration file for the Greenstone project, and \gst{build.properties} contains parameters that can be altered by the user.
+
+\subsection{Get and install \gs\ }\label{sec:getandinstall}
+
+\gsiii\  is available for download from Sourceforge:\\
+ \gst{https://sourceforge.net/projects/greenstone3}. There are Windows, Linux, and source releases. The binary releases are self-installing executables: download and run the file to install. A series of prompts will guide you through the installation process. The source release is a gzip'd tar file. Unzip and untar this, check build.properties, then run \gst{'ant install'} to configure and compile the code.
+
+The \gsiii\  library can be launched by running the server program. This is accessible from the Start menu on Windows, or by running the \gst{gs3-server.sh/bat} script in the top level \gst{greenstone3} directory. This program will start up the Tomcat web server and launch a browser.
+
+Alternatively, you can start it up using Ant: run \gst{'ant start'}, which starts up Tomcat, then in a browser go to \gst{http://localhost:8080/greenstone3}\\
+(or \gst{http://your-computer-name:your-chosen-port/greenstone3}). \\
+This gets you to a welcome page containing links to four servlets: the \gst{test} servlet (this allows you to check that Tomcat is running properly); the standard \gst{library} servlet which serves \gst{localsite} site with the \gst{default} interface; the \gst{classic} servlet which serves \gst{localsite} using the \gst{classic} or \gsii-style interface; and the \gst{gateway} servlet, which serves \gst{gateway} site with the \gst{default} interface. The \gst{gateway} site uses a SOAP connection to communicate with \gst{localsite}, and demonstrates the library working in a distributed fashion. The SOAP connection is not enabled by default - to enable it, run \gst{'ant deploy-localsite'}.
+
+\gsiii\  is also available through CVS (Concurrent Versioning System). This provides the latest development version, and is not guaranteed to be stable. Appendix~\ref{app:cvs} describes how to download and install \gsiii\  from CVS.
+
+\subsection{How the library works}
+
+The standard library program is a Java servlet. We use the Tomcat servlet container to present the servlets over the web. Tomcat takes CGI-style URLs and passes the arguments to the servlet, which processes these and returns a page of HTML. As far as an end-user is concerned, a servlet is a Java version of a CGI program. The interaction is similar: access is via a web browser, using arguments in a URL.
+
+Other types of interfaces can be used, such as Java GUI programs. See Section~\ref{sec:new-interfaces} for details about how to make these.
+
+\subsubsection{Restarting the library}
+
+You can restart Tomcat by clicking 'Restart Server' on the little server program. You should restart the server any time you make changes in the following for those changes to take effect:\\
+\begin{bulletedlist}
+\begin{gsc}
+\item \$GSDL3HOME/WEB-INF/web.xml
+\item \$GSDL3SRCHOME/packages/tomcat/conf/server.xml
+\end{gsc}
+\item any classes or jar files used by the servlets
+\end{bulletedlist}
+
+
+\subsection{Directory structure}
+
+Table~\ref{tab:dirs} shows the file hierarchy for \gsiii.
+The first part  shows the common stuff which can be shared between
+\gs\  users---the source, libraries etc. The second part shows the file hierarchy for the web directory, which comprises the greenstone3 context for Tomcat, and is accessible via Tomcat. The main directories are for sites and interfaces: there can be several sites and interfaces per installation, and they are described in the following section.
+
+Two environment variables used by \gsiii\ are often mentioned in this manual: \gst{\$GSDL3SRCHOME} and \gst{\$GSDL3HOME}. \gst{\$GSDL3SRCHOME} refers to the top-level \gst{greenstone3} directory, while \gst{\$GSDL3HOME} refers to the \gst{web} directory. The web directory contains everything needed to serve the \gsiii\ library using Tomcat, and doesn't necessarily need to live with the rest of the \gsiii\ source.
+
+\begin{table}
+\caption{The \gs\  directory structure}
+\label{tab:dirs}
+{\footnotesize
+\begin{tabular}{l p{8cm}}
+\hline
+\bf directory & \bf description \\
+\hline
+greenstone3 
+  & The main installation directory---\$GSDL3SRCHOME is set to this directory \\
+greenstone3/src 
+  & Source code lives here \\
+greenstone3/src/java/
+  & main \gsiii\  java source code \\
+greenstone3/src/packages 
+  & Imported source packages from other systems e.g. indexing packages may go here \\
+greenstone3/lib
+  & Shared library files\\
+greenstone3/lib/java
+  & Java jar files not needed in the \gsiii\  runtime\\
+greenstone3/lib/jni
+  & Jar files and shared library files (.so, .jnilib, .dll) needed for JNI components \\
+greenstone3/resources 
+ & any resources that may be needed\\
+greenstone3/resources/soap
+ & soap service description files \\
+greenstone3/bin
+  & executable stuff lives here\\
+greenstone3/bin/script
+  & some Perl and/or shell scripts\\
+greenstone3/packages
+  & External packages that may be installed as part of greenstone, e.g. Tomcat \\
+greenstone3/docs
+  & Documentation\\
+greenstone3/gli
+  & \gs\ Librarian Interface code \\
+greenstone3/gs2build
+  & collection building code\\
+\hline
+greenstone3/web
+  & This is where the web site is defined. Any static HTML files can go here. This directory is the root directory used by Tomcat when serving \gsiii. \$GSDL3HOME is set to this directory. \\
+greenstone3/web/WEB-INF
+  & The web.xml file lives here (servlet configuration information for Tomcat)\\
+greenstone3/web/WEB-INF/classes
+  & Individual class files needed by the servlet go in here, also properties files for java resource bundles - used to handle all the language specific text. This directory is on the servlet classpath\\
+greenstone3/web/WEB-INF/lib
+  & jar files needed by the servlets go here \\
+greenstone3/web/sites
+  & Contains directories for different sites---a site is a set of collections and services served by a single MessageRouter (MR). The MR may have connections (e.g. soap) to other sites\\
+greenstone3/web/sites/localsite 
+  & An example site - the site configuration file lives here\\
+greenstone3/web/sites/localsite/collect 
+  & The collections directory \\
+greenstone3/web/sites/localsite/images 
+  & Site specific images \\
+greenstone3/web/sites/localsite/transforms 
+  & Site specific transforms \\
+greenstone3/web/interfaces
+  & Contains directories for different interfaces - an interface is defined by its images and XSLT files \\
+greenstone3/web/interfaces/default
+  & The default interface\\
+greenstone3/web/interfaces/default/images
+  & The images for the default interface\\
+greenstone3/web/interfaces/default/js
+  & The javascript libraries for the default interface\\
+greenstone3/web/interfaces/default/style
+  & The CSS stylesheets for the default interface\\
+greenstone3/web/interfaces/default/transforms
+  & The XSLT files for the default interface\\
+greenstone3/web/applet 
+  & jar files needed by applets can go here \\
+\hline
+\end{tabular}}
+\end{table}
+
+
+\subsection{Sites and interfaces}\label{sec:sites-and-ints}
+
+Sites and interfaces contain the content and presentation information, respectively, for the digital library.
+A site is comprised of a set of collections and possibly some site-wide services. An interface (in this web-based servlet context) is a set of images along with a set of XSLT files used for translating xml output from the library into an appropriate form---HTML in general.
+
+One \gsiii\  installation can have many sites and interfaces, and these can be paired in different combinations.  One instantiation of a servlet uses one site and one interface, so every specified pairing results in a new servlet instance.  For example, a single site might be served with two different interfaces. This provides different modes of access to the same content. e.g. HTML vs WML, or perhaps providing a completely different look and feel for different audiences. Alternatively, a standard interface may be used with many different sites---providing a consistent mode of access to a lot of different content.
+
+Collections live in the \gst{collect} directory of a site. Any collections that are found in this directory when the servlet is initialized will be loaded up. Public collections will appear on the library home page, while private collections will be hidden. These can still be accessed by typing in cgi arguments. Collections require valid configuration files, but apart from this, nothing needs to be done to the site to use new collections. Collections added while Tomcat is running will not be noticed automatically. Either the server needs to be restarted, or a configuration request may be sent to the library, triggering a (re)load of the collection (this is described in Section~\ref{sec:runtime-config}).
+
+There are two  sites that come with the distribution: \gst{localsite}, and \gst{gateway}. \gst{localsite} has several demo  collections, while \gst{gateway} has none. \gst{gateway} specifies that a SOAP connection should be made to \gst{localsite}. Getting this to work involves setting up a soap server for localsite: see Section~\ref{sec:distributed} for details. 
+There are also two interfaces provided in the distribution: \gst{default} and \gst{classic}. The default interface is a generic \gsiii\ interface, while the \gst{classic} interface aims to look like the old \gsii\ interface.
+
+Each site and interface has a configuration file which specifies parameters for the site or interface---these are described in Section~\ref{sec:config}.
+
+\subsection{Configuring Tomcat}\label{sec:tomcat-config}
+
+The file \gst{\$GSDL3HOME/WEB-INF/web.xml} contains the configuration information for Tomcat. It tells Tomcat what servlets to load, what initial parameters to pass them, and what web names map to the servlets.
+There are four servlets specified in web.xml (these correspond to the four servlet links in the welcome page for \gsiii): one is a test servlet that just prints ``hello greenstone'' to a web page. This is useful if you are having trouble getting Tomcat set up. The other three are the \gs\  library servlets described in Section~\ref{sec:getandinstall}, \gst{library}, \gst{classic} and \gst{gateway}. Each servlet must specify which site and which interface to use. Having multiple servlets provides a way of serving different sites, or the same site with a different style of presentation. \gst{site\_name} and \gst{interface\_name} are just two examples of initialization parameters used by the library servlets. The full list is shown in Table~\ref{tab:serv-init}. 
+
+For more details about Tomcat see Appendix~\ref{app:tomcat}.
+
+\begin{table}
+\caption{\gs\  servlet initialization parameters}
+\label{tab:serv-init}
+{\footnotesize
+\begin{tabular}{lp{3.5cm}p{6cm}}
+\hline
+\bf name & \bf sample value & \bf description \\
+\hline
+library\_name & library & the web name of the servlet \\
+interface\_name & default & the name of the interface to use\\
+site\_name & localsite & the name of the local site to use (use either site\_name or the three remote\_site parameters)\\
+remote\_site\_name & org.greenstone.site1 & the name of a remote site (can be anything??) \\
+remote\_site\_type & soap & the type of server running on the site \\
+remote\_site\_address & http://www.greenstone.org/ greenstone3/services/ localsite & The address of the server \\
+default\_lang & en & the default language for the interface\\
+receptionist\_class & NZDLReceptionist & (optional) specifies an alternative Receptionist to use\\
+messagerouter\_class & NewMessageRouter & (optional) specifies an alternative MessageRouter to use\\
+params\_class & NZDLParams & (optional) specifies an alternative GSParams class to use \\
+\hline
+\end{tabular}}
+\end{table}
+
+\subsection{Configuring a \gs\ library}\label{sec:config}
+
+Initial \gsiii\  system configuration is determined by a set of XML configuration files. Each site has a configuration file that binds parameters for the site, \gst{siteConfig.xml}. Each interface has a configuration file, \gst{interfaceConfig.xml}, that specifies parameters for the interface. Collections also have several configuration files; these are discussed in Section~\ref{sec:collconfig}. 
+The configuration files are read in when the system is initialized, and their contents are cached in memory. This means that changes made to these files once the system is running will not take immediate effect. Tomcat needs to be restarted for changes to the interface configuration file to take effect. However, changes to the site configuration file can be incorporated sending a system command to the library.  There are a series of system commands that can be sent to the library to induce reconfiguration of different modules, including reloading the whole site. This removes the need to restart the system to reflect these changes. These commands are described in Section~\ref{sec:runtime-config}.
+
+\subsubsection{Site configuration file}\label{sec:siteconfig}
+
+The file \gst{siteConfig.xml} specifies the URI for the site (\gst{localSiteName}), the HTTP address for site resources (\gst{httpAddress}), any \gst{ServiceClusters} that the site provides (for example, collection building), any \gst{ServiceRacks} that do not belong to a cluster or collection, and a list of
+known external sites to connect to.  Collections are not specified in the site
+configuration file, but are determined by the contents of the site's
+collect directory.
+
+The HTTP address is used for retrieving resources from a site outside the XML protocol. Because a site is HTTP accessible through Tomcat, any files (e.g. images) belonging to that site or to its collections can be specified in the HTML of a page by a URL. This avoids having to retrieve these files from a remote site via the XML protocol\footnote{Currently, sites live inside the Tomcat greenstone3 root context, and therefore all their content is accessible over HTTP via the Tomcat address. We need to see if parts can be restricted. Also, if we use a different protocol, then resources from remote sites may need to come through the XML. Also, if we are running locally without using Tomcat, we may want to get them via file:// rather than http://.}.
+ 
+Figure~\ref{fig:siteconfig} shows two example site configuration files. The first example is for a rudimentary site with no site-wide services,
+which does not connect to any external sites. The second example is for a site with one site-wide service cluster - a collection building cluster.  It also connects to the first site using SOAP.
+These two sites happen to be running on the same machine, which is why they can use \gst{localhost} in the address. For site \gst{gsdl1} to talk to site \gst{localsite}, a SOAP server must be run for \gst{localsite}. The address of the SOAP server, in this case, is \gst{http://localhost:8080/greenstone3/services/localsite}.
+
+
+\begin{figure}
+\begin{gsc}\begin{verbatim}
+<siteConfig>
+  <localSiteName value="org.greenstone.localsite"/>
+  <httpAddress value="http://localhost:8080/greenstone3/sites/localsite"/>
+  <serviceClusterList/>
+  <serviceRackList/>
+  <siteList/>
+</siteConfig>
+\end{verbatim}\end{gsc}
+
+\begin{gsc}\begin{verbatim}
+<siteConfig>
+  <localSiteName value="org.greenstone.gsdl1"/>
+  <httpAddress value="http://localhost:8080/greenstone3/sites/gsdl1"/>
+  <serviceClusterList>	
+    <serviceCluster name="build">
+      <metadataList>
+        <metadata name="Title">Collection builder</metadata>
+        <metadata name="Description">Builds collections in a 
+           gsdl2-style manner</metadata>
+      </metadataList>
+      <serviceRackList>
+        <serviceRack name="GS2Construct"/>
+      </serviceRackList>
+    </serviceCluster>
+  </serviceClusterList>
+  <siteList>
+    <site name="org.greenstone.localsite"
+      address="http://localhost:8080/greenstone3/services/localsite"
+      type="soap"/>
+  </siteList>
+</siteConfig>
+\end{verbatim}\end{gsc}
+\caption{Two sample site configuration files}
+\label{fig:siteconfig}
+\end{figure}
+
+Another element that can appear in a site configuration file is \gst{replaceList}. This must have an \gst{id} attribute, and may contain one or more \gst{replace} elements. Replace elements are discussed in Section \ref{sec:collconfig}. The list found in a \gst{siteConfig.xml} file can be applied to any collection by adding a \gst{replaceListRef} element (with the appropriate \gst{id} attribute) to its \gst{collectionConfig.xml} file.
+
+\subsubsection{Interface configuration file}\label{sec:interfaceconfig}
+
+The interface configuration file \gst{interfaceConfig.xml} lists all the actions that the interface knows about at the start (other ones can be loaded dynamically). Actions create the web pages for the library: there is generally one Action per type of page. For example, a query action produces the pages for searching, while a document action displays the documents. The configuration file specifies what short name each action maps to (this is used in library URLs for the a (action) parameter) e.g. QueryAction should use \gst{a=q}. If the interface uses XSLT, it specifies what XSLT file should be used for each action and possibly each subaction. This makes it easy for developers to implement and use different actions and/or XSLT files without recompilation. The server must be restarted, however.
+
+It also lists all the languages that the interface text files have been translated into. These have a \gst{name} attribute, which is the ISO code for the language, and a \gst{displayElement} which gives the language name in that language (note that this file should be encoded in UTF-8). This language list is used on the Preferences page to allow the user to change the interface language. Details on how to add a new language to a \gsiii\  library are shown in Section~\ref{sec:interface-language}.
+
+An \gst{optionList} element can be used to disable or enable some optional functionality for the interface. Currently there are three options that can be enabled:
+
+\begin{tabular}{lp{7cm}}
+highlightQueryTerms & Whether search term highlighting is available or not\\
+berryBaskets & Whether berry basket functionality is available or not\\
+displayAnnotationService & Whether any annotation services (specified in the site config file) should be displayed with a document or not. \\
+\end{tabular}
+
+An interface may be based on an existing one, for example, the classic interface is based on the default interface. This means that it will use any images or templates from the base one unless overridden in the current one. The \gst{baseInterface} attribute of the \gst{<interfaceConfig>} element is used to specify the base interface.
+ 
+\begin{figure}
+\begin{gsc}\begin{verbatim}
+<interfaceConfig>
+  <actionList>
+    <action name='p' class='PageAction'>
+      <subaction name='home' xslt='home.xsl'/>
+      <subaction name='about' xslt='about.xsl'/>
+      <subaction name='help' xslt='help.xsl'/>
+      <subaction name='pref' xslt='pref.xsl'/>
+      <subaction name='nav' xslt='nav.xsl'/><!-- used for the 
+            collection header frame -->
+      <subaction name="html" xslt="html.xsl"/> <!-- used to put an 
+            external page into a frame with a collection header-->
+    </action>
+    <action name='q' class='QueryAction' xslt='basicquery.xsl'/>
+    <action name='b' class='GS2BrowseAction' xslt='classifier.xsl'/>
+    <action name='a' class='AppletAction' xslt='applet.xsl'/>
+    <action name='d' class='DocumentAction' xslt='document.xsl'/>
+    <action name='xd' class='XMLDocumentAction'>
+      <subaction name='toc' xslt='document-toc.xsl'/>
+      <subaction name='text' xslt='document-content.xsl'/>
+    </action>
+    <action name='pr' class='ProcessAction' xslt='process.xsl'/>
+    <action name='s' class='SystemAction' xslt='system.xsl'/>
+    <action name='g' class='GeneralAction'>
+      <subaction name="berry" xslt='berry.xsl'/>
+    </action>
+  </actionList>
+  <languageList>
+    <language name="en">
+      <displayItem name='name'>English</displayItem>
+    </language>
+    <language name="fr">
+      <displayItem name='name'>Français</displayItem>
+    </language>
+    <language name='es'>
+      <displayItem name='name'>Español</displayItem>
+    </language>
+  </languageList>
+  <optionList>
+    <option name="highlightQueryTerms" value="true"/>
+    <option name="berryBaskets" value="true"/>
+  </optionList>
+</interfaceConfig>
+\end{verbatim}\end{gsc}
+\caption{Default interface configuration file}
+\label{fig:ifaceconfig}
+\end{figure}
+
+
+\subsection{Run-time re-initialization}\label{sec:runtime-config}
+
+When Tomcat is started up, the site and interface configuration files are read in, and actions/services/collections loaded as necessary. The configuration is then static unless Tomcat is restarted, or re-configuration commands issued. 
+
+There are several commands that can be issued to Tomcat to avoid having to restart the server. These can reload the entire site, or just individual collections. Unfortunately at present there are no commands to reconfigure the interface, so if the interface configuration file has changed, Tomcat must be restarted for those changes to take effect. Similarly, if the Java classes are modified, Tomcat must be restarted then too.
+
+Currently, the runtime configuration commands can only be accessed by typing arguments into the URL; there is no nice web form yet to do this. 
+
+The arguments are entered after the \gst{library?} part of the URL. There are three types of commands: configure, activate, deactivate. These are specified by \gst{a=s\&sa=c}, \gst{a=s\&sa=a}, and \gst{a=s\&sa=d}, respectively (\gst{a} is action, \gst{sa} is subaction). By default, the requests are sent to the MessageRouter, but they can be sent to a collection/cluster by the addition of \gst{sc=xxx}, where \gst{xxx} is the name of the collection or cluster. Table~\ref{tab:run-time config} describes the commands and arguments in a bit more detail.
+
+\begin{table}
+\caption{Example run-time configuration arguments.}
+\label{tab:run-time config}
+{\footnotesize
+\begin{tabular}{lp{9cm}}
+\hline
+\gst{a=s\&sa=c} & reconfigures the whole site. Reads in siteConfig.xml, reloads all the collections. Just part of this can be specified with another argument \gst{ss} (system subset). The valid values are \gst{collectionList}, \gst{siteList}, \gst{serviceList}, \gst{clusterList}. \\
+\gst{a=s\&sa=c\&sc=XXX} & reconfigures the XXX collection or cluster. \gst{ss} can also be used here, valid values are \gst{metadataList} and \gst{serviceList}. \\
+\gst{a=s\&sa=a} & (re)activate a specific module. Modules are specified using two arguments, \gst{st} (system module type) and \gst{sn} (system module name). Valid types are \gst{collection}, \gst{cluster} \gst{site}.\\
+\gst{a=s\&sa=d} & deactivate a module. \gst{st} and \gst{sn} can be used here too. Valid types are \gst{collection}, \gst{cluster}, \gst{site}, \gst{service}. Modules are removed from the current configuration, but will reappear if Tomcat is restarted.\\
+\gst{a=s\&sa=d\&sc=XXX} & deactivate a module belonging to the XXX collection or cluster. \gst{st} and \gst{sn} can be used here too. Valid types are \gst{service}. \\
+\hline
+\end{tabular}}
+\end{table}
+\newpage
+\section{Using \gsiii\ }\label{sec:user}
+
+Once \gsiii\ is installed, the sample collections can be accessed. The installation comes with several example collections, and Section~\ref{sec:usecolls} describes these collections and how to use them. Section~\ref{sec:buildcol} describes how to build new collections.
+
+\subsection{Using a collection}\label{sec:usecolls} 
+
+A collection typically consists of a set of documents, which could be text, HTML, word, PDF, images, bibliographic records etc, along with some access methods, or ``services''. Typical access methods include searching or browsing for document identifiers, and retrieval of content or metadata for those identifiers.
+Searching involves entering words or phrases and getting back lists of documents that contain those words. The search terms may be restricted to particular fields of the document. 
+
+Browsing involves navigating pre-defined hierarchies of documents, following links of interest to find documents. The hierarchies may be constructed on different metadata fields, for example, alphabetical lists of Titles, or a hierarchy of Subject classifications. Clicking on a bookshelf icon takes you to a lower level in the hierarchy, while clicking on a book or page icon takes you to a document.
+
+In the standard interface that comes with \gsiii\ \footnote{of course, this is all customizable}, collections in a digital library are presented in the following manner. The 'home' page of the library shows a list of all the public collections in that library. Clicking on a collection link takes you to the home page for the collection, which we call the collection's 'about' page. The standard page banner for a collection looks something like that shown in Figure~\ref{fig:page-banner}.
+
+\begin{figure}[h]
+  \centering
+  \includegraphics[width=4in]{pagebanner.ps} %5.8
+  \caption{A sample collection page banner}
+  \label{fig:page-banner}
+\end{figure}
+
+The image at the top left is a link to the collection's home page. The top right has buttons to link to the library home page, help and preferences pages. All the available services are arrayed along a navigation bar, along the bottom of the banner. Clicking on a name accesses that service. 
+
+Search type services generally provide a form to fill in, with parameters including what field or granularity to search, and the query itself. Clicking the search button carries out the search, and a list of matching documents will be displayed. Clicking on the icons in the result list takes you to the document itself. 
+
+Once you are looking at a document, clicking the open book icon at the top of the document, underneath the navigation bar, will take you back to the service page that you accessed the document from.
+
+\subsection{Building a collection}\label{sec:buildcol}
+
+There are three ways to get a new collection into \gsiii. The most common way is to use the Greenstone Librarian Interface to create a collection. If you have existing collections in a \gsii\ installation, these can be imported into \gsiii. Thirdly, you can use the Perl command line building scripts directly.
+
+Collections live in the \gst{collect} directory of a site. As described in Section~\ref{sec:sites-and-ints}, there can be several sites per \gsiii\  installation. The collect directory is at \gst{\$GSDL3HOME/sites/site-name/collect}, where site-name is the name of the site you want your new collection to belong to.
+
+The following three sections briefly  describe how to create a collection using GLI, how to import a collection from \gsii, and how to use command line building.  Once a collection has been built (and is located in the collect directory), the library server needs to be notified that there is a new collection. This can be accomplished in two ways\footnote{and eventually there will also probably be automatic polling for new collections}. If you are the library administrator, you can restart Tomcat. The library servlet will then be created afresh, and will discover the new collection when it scans the collect directory for the collection list. Alternatively, an activate collection command can be issued to the servlet, using the arguments \gst{a=s\&sa=a\&st=collection\&sn=collname}, where \gst{collname} should be replaced with the collection name---this tells the library program to (re)load the \gst{collname} collection.
+
+\subsubsection{Using the Librarian Interface}
+
+The Greenstone Librarian Interface (GLI) can be used to create collections. The procedure is the same as for \gsii, but it works in a \gsiii\  context. It can be started under Windows by selecting Greenstone Librarian Interface from the Greenstone 3 Digital Library menu in the Program Files section of the Start menu. On Linux, run \gst{ant gli} from the \gst{greenstone3} directory, or run \gst{./gli4gs3.sh} from the \gst{\$GSDL3SRCHOME/gli} directory.
+
+Currently, the GLI works almost exactly the same as for \gsii\footnote{Eventually the GLI will be modified to use \gsiii\ XML  configuration files.}. Collection configuration is done in a \gsii\ manner. The main difference is that \gsiii\ has different sites and interfaces and servlets, whereas \gsii\ has a single collect directory, and a single runtime cgi program.
+
+The GLI for \gsiii\ has a couple of new configuration parameters: site and servlet. It operates within a single site---you can edit, delete, and create new collections within this site. A servlet is also specified for that site---this is used when previewing a collection. While you are working in one site, you cannot edit collections from another site. However, you can base a collection on one from another site. To change the working site and/or servlet, go to Preferences-$>$Connection in the File menu. By default, the GLI will use site \gst{localsite}, and servlet \gst{library}.
+
+Collection building using the GLI will use the \gsii\ Perl scripts and plugins. At the conclusion of the \gsii\ build process, a conversion script will be run to create the \gsiii\  configuration files. This means that format statements are no longer 'live'---changing these will require changes to the \gsiii\ configuration files. Clicking the Preview Collection button will re-run the configuration file conversion script. If you change anything on the Format panel, you will need to click Preview Collection. Just reloading the collection via a browser will not be enough. 
+ 
+Detailed instructions about using the GLI can be found in Sections 3.1 and 3.2 of the \gsii\  User's Guide (\gst{GS2-User-en.pdf}). This can be found in  your \gsii\ installation, or in the \gst{\$GSDL3SRCHOME/docs/manual} directory if you have installed \gsiii\ from a distribution.
+
+
+\subsubsection{Importing from \gsii}
+
+Pre-built \gsii\ collections can also be used in \gsiii. The collection folder should be copied to the collect directory of the site it is to appear in (or a symbolic link may be used if possible).
+The \gsiii\  run time system requires different configuration files for a collection, so you need to run a conversion script. All this does is create the new \gst{collectionConfig.xml} and \gst{buildConfig.xml} from the old \gst{collect.cfg} and \gst{build.cfg} files. It does not change the collection in any way, so it can still be used by \gsii\  software.
+
+The conversion script is \gst{convert\_coll\_from\_gs2.pl}. To run it, make sure you have run \gst{source setup.bash} (or \gst{setup} in Windows) in the \gst{\$GSDL3SRCHOME/gs2build} directory (as well as running the standard \gst{gs3-setup} command). Then you need to specify the path to the collect directory and the collection name as parameters to the conversion script. For example, 
+
+\begin{gsc}
+\begin{verbatim}
+convert_coll_from_gs2.pl -collectdir 
+   $GSDL3HOME/sites/localsite/collect gs2mgdemo
+\end{verbatim}
+\end{gsc}
+%$
+The script attempts to create \gsiii\  format statements from the old \gsii\  ones. The conversion may not always work properly, so if the collection looks a bit strange under \gsiii, you should check the format statements. Format statements are described in Section~\ref{sec:formatstmt}.
+
+Once again, to have the collection recognized by the library servlet, you can either restart Tomcat, or load it dynamically.
+
+\subsubsection{Using command line building}
+
+This is the same procedure as for \gsii\ command line building, with the addition of a final step to create the \gsiii\ configuration files. The basic steps are (for a new collection called testcol):
+
+Linux:
+
+\begin{gsc}
+\begin{verbatim}
+cd greenstone3
+source gs3-setup.sh
+cd gs2build
+source setup.bash
+cd ../
+mkcol.pl -collectdir $GSDL3HOME/sites/localsite/collect testcol
+put source documents and metadata into 
+            $GSDL3HOME/sites/localsite/collect/testcol/import
+edit $GSDL3HOME/sites/localsite/collect/testcol/etc/collect.cfg as 
+            appropriate
+import.pl -collectdir $GSDL3HOME/sites/localsite/collect testcol
+buildcol.pl -collectdir $GSDL3HOME/sites/localsite/collect testcol
+rename the $GSDL3HOME/sites/localsite/collect/testcol/building 
+            directory to index
+convert_coll_from_gs2.pl -collectdir $GSDL3HOME/sites/localsite/collect 
+            testcol
+%$
+\end{verbatim}
+\end{gsc}
+
+Windows:
+\begin{gsc}
+\begin{verbatim}
+cd greenstone3
+gs3-setup
+cd gs2build
+setup
+cd ..
+perl -S mkcol.pl -collectdir %GSDL3HOME%\sites\localsite\collect testcol
+put source documents and metadata into 
+            %GSDL3HOME%\sites\localsite\collect\testcol\import
+edit %GSDL3HOME%\sites\localsite\collect\testcol\etc\collect.cfg as 
+            appropriate
+perl -S import.pl -collectdir %GSDL3HOME%\sites\localsite\collect testcol
+perl -S buildcol.pl -collectdir %GSDL3HOME%\sites\localsite\collect testcol
+rename the %GSDL3HOME%\sites\localsite\collect\testcol\building directory 
+            to index
+perl -S convert_coll_from_gs2.pl -collectdir 
+            %GSDL3HOME%\sites\localsite\collect testcol
+\end{verbatim}
+\end{gsc}
+
+Once the build process is complete, Tomcat should be prompted to reload the collection---either by restarting the server, or by sending an activate collection command to the library servlet.
+
+Metadata for documents can be added using \gst{metadata.xml} files.  A \gst{metadata.xml} file has a root element of \gst{<DirectoryMetadata>}.  This encloses a series of \gst{<FileSet>} items.  Neither of these tags has any attributes.  Each \gst{<FileSet>} item includes two parts: firstly, one or more \gst{<FileName>} tags, each of which encloses a regular expression to identify the files which are to be assigned the metadata.  Only files in the same directory as the \gst{metadata.xml} file, or in one of its child directories, will be selected.  The filename tag encloses the regular expression as text, e.g.:
+
+\begin{gsc}\begin{verbatim}
+<FileName>example</FileName>
+\end{verbatim}\end{gsc}
+
+This would match any file containing the text 'example' in its name.  The second part of the \gst{<FileSet>} item is a \gst{<Description>} item.  The \gst{<Description>} tag has no attributes, but encloses one or more \gst{<Metadata>} tags.  Each \gst{<Metadata>} tag contains one metadata item, i.e. a label to describe the metadata and a corresponding value.  The \gst{<Metadata>} tag has one compulsory attribute: \gst{'name'}.  This attribute gives the metadata label to add to the document.  Each \gst{<Metadata>} tag also has an optional attribute: \gst{'mode'}.  If this attribute is set to \gst{'accumulate'} then the value is added to the document, and any existing values for that metadata item are retained.  If the attribute is set to \gst{'set'} or is omitted, then any existing value of the metadata item will be deleted.
+
+\begin{figure}
+\begin{gsc}\begin{verbatim}
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE DirectoryMetadata SYSTEM "http://greenstone.org/dtd/DirectoryMetadata
+         /1.0/DirectoryMetadata.dtd">
+<DirectoryMetadata>
+  <FileSet>
+    <FileName>ec160e</FileName>
+    <Description>
+      <Metadata name="Title">The Courier - No.160 - Nov - Dec 1996 - 
+         Dossier Habitat - Country reports: Fiji , Tonga (ec160e)</Metadata>
+      <Metadata mode="accumulate" name="Language">English</Metadata>
+      <Metadata mode="accumulate" name="Subject">Settlements and housing: 
+        general works incl. low- cost housing, planning techniques, surveying, 
+        etc.</Metadata>
+      <Metadata mode="accumulate" name="Subject">The Courier ACP 1990 - 1996 
+        Africa-Caribbean-Pacific - European Union</Metadata>
+      <Metadata mode="accumulate" name="Organization">EC Courier</Metadata>
+      <Metadata mode="accumulate" name="AZList">T.1</Metadata>
+    </Description>
+  </FileSet>
+  <FileSet>
+    <FileName>b22bue</FileName>
+    <Description>
+      <Metadata name="Title">Butterfly Farming in Papua New Guinea 
+        (b22bue)</Metadata>
+      <Metadata mode="accumulate" name="Language">English</Metadata>
+      <Metadata mode="accumulate" name="Subject">Other animals (micro-
+        livestock, little known animals, silkworms, reptiles, frogs, 
+        snails, game, etc.)</Metadata>
+      <Metadata mode="accumulate" name="Organization">BOSTID</Metadata>
+      <Metadata mode="accumulate" name="AZList">T.1</Metadata>
+      <Metadata mode="accumulate" name="Keyword">start a butterfly farm
+        </Metadata>
+    </Description>
+  </FileSet>
+</DirectoryMetadata>
+\end{verbatim}\end{gsc}
+\caption{Sample metadata.xml file}
+\label{fig:metadatafile}
+\end{figure}
+
+Figure~\ref{fig:metadatafile} shows an example metadata.xml file.
+Here, only one file pattern is found in each file set.  However, the \gst{Description} tag contains a number of separate metadata items.  Note that the \gst{Title} metadata does not have the \gst{mode=accumulate} attribute.  This means that when this title is assigned to a document, any existing \gst{Title} information will be lost.
+
+
+\subsection{Collection configuration files}\label{sec:collconfig}
+
+Each collection has two, or possibly three, \gsiii\ configuration files, \\
+\gst{collectionConfig.xml}, \gst{buildConfig.xml}, and optionally \gst{collectionInit.xml}, that give metadata, display and other information for the
+collection. Currently, \gst{collectionConfig.xml} and \gst{buildConfig.xml} are generated from \gst{collect.cfg} and \gst{build.cfg}. At some stage, the collection building process and the Librarian Interface will be modified to use these files directly. 
+\gst{collect.cfg} and/or \gst{collectionConfig.xml} includes user-defined presentation metadata for the collection, such as its name and the {\em About this collection} text; gives formatting information for the collection display; and also gives instructions on how the collection is to be built. \gst{build.cfg} and/or \gst{buildConfig.xml} are produced by the build-time process and include any metadata that can be determined automatically. It also includes configuration information for any ServiceRacks needed by the collection.
+
+All the configuration files should be encoded using UTF-8.
+
+The format of \gst{collect.cfg} and \gst{build.cfg} are not discussed here. Please see the \gsii\ manuals for more information regarding these files.
+
+\subsubsection{collectionInit.xml}
+
+This optional file is only used for non-standard, customized collections. It specifies the class name of the non-standard collection class.  The only syntax so far is the class name:
+
+\begin{gsc}\begin{verbatim}
+<collectionInit class="XMLCollection"/>
+\end{verbatim}\end{gsc}
+
+Section~\ref{sec:new-coll-types} describes an example collection where this file is used. Depending on the type of collection that this is used for, one or both of the other configuration files may not be needed.
+
+\subsubsection{collectionConfig.xml}
+
+The collection configuration file is where the collection designer (e.g. a librarian) decides what form the collection should take. So far this file only includes the presentation aspects needed by the run-time system. Instructions for collection building have yet to be defined. Presentation aspects include collection metadata such as title and description, display text for indexes, and format statements for search results, classifiers etc. The format of \gst{collectionConfig.xml} is still under consideration. However, Figure~\ref{fig:collconfig} shows the parts of it that have been defined so far. 
+
+Display elements for a collection can be entered in any language---use \gst{lang='en'} attributes to specify which language they are in.
+
+\begin{figure}
+\begin{gsc}\begin{verbatim}
+<collectionConfig xmlns:gsf="http://www.greenstone.org/greenstone3/
+  schema/ConfigFormat" xmlns:xslt="http://www.w3.org/1999/XSL/Transform">
+  <metadataList>
+    <metadata name="creator">greenstone@cs.waikato.ac.nz</metadata>
+    <metadata name="public">true</metadata>
+  </metadataList>
+  <displayItemList>
+    <displayItem name='name' lang='en'>Greenstone3 MG demo collection</displayItem>
+    <displayItem name='description' lang='en'>This is a demonstration 
+      collection for the Greenstone3 digital library software.</displayItem>
+    <displayItem name='icon' lang='en'>gs3mgdemo.gif</displayItem>
+    <displayItem name='smallicon' lang='en'>gs3mgdemo_sm.gif</displayItem>
+  </displayItemList>
+  <search>
+    <index name="ste">
+      <displayItem name='name' lang="en">chapters</displayItem>
+      <displayItem name='name' lang="fr">chapitres</displayItem>
+      <displayItem name='name' lang="es">capÃ­tulos</displayItem>
+    </index>
+    [ ... more indexes ...]
+    <format>
+      <gsf:template match="documentNode"><td valign='top'>
+       <gsf:link><gsf:icon/></gsf:link></td><td><gsf:metadata name='Title'/>
+      </td></gsf:template>
+    </format>
+  </search>
+  <browse>
+    <classifier name="CL1" horizontalAtTop='true'>
+      <displayItem name='name' lang='en'>Titles</displayItem>
+    </classifier>
+    [... more classifiers ...]
+    <classifier name="CL4">
+      <displayItem name='name' lang='en'>HowTo</displayItem>
+      <format>
+        <gsf:template match="documentNode">
+          <br /><gsf:link><gsf:metadata name='Keyword' />
+            </gsf:link></gsf:template>
+      </format>
+    </classifier>
+  </browse>
+  <display>
+    <format>
+      <gsf:option name="coverImages" value="false"/>
+      <gsf:option name="documentTOC" value="false"/>
+    </format>
+  </display>
+</collectionConfig>
+\end{verbatim}\end{gsc}
+\caption{Sample collectionConfig.xml file}
+\label{fig:collconfig}
+\end{figure}
+
+The \gst{<metadataList>} element specifies some collection metadata, such as creator. The \gst{<displayItemList>} specifies some language dependent information that is used for collection display, such as collection name and short description. These \gst{displayItem} elements can be specified in different languages. 
+ 
+The \gst{<search>} element provides some display and formatting information for the search indexes, while the \gst{<browse>} element concerns classifiers, and   the \gst{<display>} element looks at document display. 
+
+Inside the \gst{<search>} and \gst{<browse>} elements, \gst{<displayItem>} elements are used to provide titles for the indexes or classifiers, while \gst{<format>} elements provide formatting instructions, typically for a document or classifier node in a list of results. Placing the \gst{<format>} instructions at the top level in the \gst{search} or \gst{browse} element will apply the format to all the indexes or classifiers, while placing it inside an individual \gst{index} or \gst{classifier} element will restrict that formatting instruction to that item.
+
+The \gst{<display>} element contains optional formatting information for the display of documents. Templates that can be specified here include \gst{documentHeading} and \gst{DocumentContent}. Other formatting options may also be specified here, such as whether to display a table of contents and/or cover image for the documents.
+
+Format elements are described in Section~\ref{sec:formatstmt}.
+
+An optional \gst{<replaceList>} element can be included at the top level. This contains a list of strings and their replacements. This is particularly useful for \gsii\  collections that use macros. 
+
+The format is like the following:
+\begin{gsc}\begin{verbatim}
+<replaceList>
+<replace scope='text' macro="xxx" text="yyy"/>
+<replace scope='metadata' macro="xxx" bundle="yyy" key="zzz"/>
+<replace scope='all' macro='xxx' metadata='yyy'/>
+</replaceList>
+\end{verbatim}\end{gsc}
+
+Scope determines on what text the replacements are carried out: \gst{text}, \gst{metadata}, and \gst{all} (both text and metadata). An empty scope attribute is equivalent to scope=all. Each replace type can be used with all scope values. Replacing uses Java's 'String.replaceAll' functionality, so macro and replacement text are actually regular expressions. The first example is a straight textual replacement. The second example uses dictionary lookups. xxx will be replaced with the (language-dependent) value for key zzz in resource bundle yyy. The third example uses metadata: xxx will be replaced by the value of the yyy metadata for that document.
+
+Appendix~\ref{app:gs2replace} gives some examples that have been used for \gsii\  collections.
+
+\subsubsection{buildConfig.xml}\label{sec:buildconfig}
+
+The file \gst{buildConfig.xml} is produced by the collection building process. Generally it is not necessary to look at this file, but it can be useful in determining what went wrong if the collection doesn't appear quite the way it was planned.
+
+It contains metadata and other information about the collection that can
+be determined automatically, such as the number of
+documents in the collection.  It also includes a list of \gst{ServiceRack} classes that are
+required to provide the services that have been built into the
+collection.  The serviceRack names are Java classes that are loaded
+dynamically at runtime. Any information inside the serviceRack element is
+specific to that service---there is no set format. Figure~\ref{fig:buildconfig} shows an example. This configuration file specifies that the collection should load up 3 ServiceRacks: \gst{GS2Browse}, \gst{GS2MGPPRetrieve} and \gst{GS2MGPPSearch}. The contents of each \gst{<serviceRack>} element are passed to the appropriate ServiceRack objects for configuration. The \gst{collectionConfig.xml} file content is also passed to the ServiceRack objects at configure time---the \gst{format} and \gst{displayItem} information is used directly from the \gst{collectionConfig.xml} file rather than added into \gst{buildConfig.xml} during building. This enables formatting and metadata changes in \gst{collectionConfig.xml} to take effect in the collection without rebuilding being necessary. However, as these files are cached, the collection needs to be reloaded for the changes to appear in the library.
+
+
+\begin{figure}
+\begin{gsc}\begin{verbatim}
+<buildConfig>
+  <metadataList>
+    <metadata name="numDocs">11</metadata>
+    <metadata name="buildType">mgpp</metadata>
+  </metadataList>
+  <serviceRackList>
+    <serviceRack name="GS2Browse">
+      <indexStem name="gs2mgppdemo"/>
+      <classifierList>
+        <classifier name="CL1" content="Title"/>
+        <classifier name="CL2" content="Subject" />
+        <classifier name="CL3" content="Organization" />
+        <classifier name="CL4" content="Howto" />
+      </classifierList>
+    </serviceRack>
+    <serviceRack name="GS2MGPPRetrieve">
+      <indexStem name="gs2mgppdemo"/>
+      <defaultLevel name="Sec" />
+    </serviceRack>
+    <serviceRack name="GS2MGPPSearch">
+      <indexStem name="gs2mgppdemo"/>
+      <defaultLevel name="Sec" />
+      <levelList>
+        <level name="Sec" />
+        <level name="Doc" />
+      </levelList>
+      <fieldList>
+        <field shortname="ZZ" name="allfields" />
+        <field shortname="TX" name="text" />
+        <field shortname="DL" name="dls.Title" />
+        <field shortname="DS" name="dls.Subject" />
+        <field shortname="DO" name="dls.Organization" />
+      </fieldList>
+      <searchTypeList>
+        <searchType name="form" />
+        <searchType name="plain" />
+      </searchTypeList>
+      <indexOptionList>
+        <indexOption name="stemIndexes" value="3"/>
+	<indexOption name="maxnumeric" value="4"/>
+      </indexOptionList>
+      <defaultIndex name="idx" />
+      <indexList>
+        <index name="idx" />
+      </indexList>
+    </serviceRack>
+  </serviceRackList>
+</buildConfig>
+\end{verbatim}\end{gsc}
+\caption{Sample buildConfig.xml file (gs2mgppdemo collection)}
+\label{fig:buildconfig}
+\end{figure}
+
+\subsection{Formatting the collection}\label{sec:formatstmt}
+
+Part of collection design involves deciding how the collection should look. \gsiii\  has a default 'look' for a collection, so this is optional. However, the default may not suit the purposes of some collections, so many parts to the look of a collection can be determined by the collection designer.
+
+In standard \gsiii, the library is served to a web browser by a servlet, and the HTML is generated using XSLT. XSLT templates are used to format all the parts of the pages. These templates can be overridden by including them in the \gst{collectionConfig.xml} file. Some commonly overridden templates are those for formatting lists: search results list, classifier browsing hierarchies, and for parts of the document display. 
+
+Real XSLT templates for formatting search results or classifier lists are quite complicated, and not at all easy for a new user to write. For example, the following is a sample template for formatting a classifier list, to show Keyword metadata as a link to the document.
+ 
+\begin{gsc}\begin{verbatim}
+<xsl:template match="documentNode" priority="2"
+     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <xsl:param name="collName"/>
+    <td><a href="{$library_name}?a=d&amp;c={$collName}&amp;
+           d={@nodeID}&amp;dt={@docType}"><xsl:value-of 
+           select="metadataList/metadata[@name='Keyword']"/></a>
+    </td>
+</xsl:template>
+ \end{verbatim}\end{gsc}
+ 
+To write this, the user would need to know that:
+\begin{bulletedlist}
+\item the variable \gst{\$library\_name} exists,
+\item the collection name is passed in as a parameter called \gst{collName}
+\item metadata for a document is found in a \gst{<metadataList>} and that its form is \gst{<metadata name="Keyword">the value</metadata>}
+\item the arguments needed for the link to the document are \gst{a, sa, c, d, a, dt}.
+\end{bulletedlist}
+ 
+We can use XSLT to transform XML into XSLT. \gsiii\  provides a simplified set of formatting commands, written in XML, which will be transformed into proper XSLT. The user specifies a \gst{<gsf:template>} for what they want to format---these typically match \gst{documentNode} or \gst{classifierNode} (for a node in a classification hierarchy).
+ 
+The template above can be represented as:
+ 
+\begin{gsc}\begin{verbatim}
+<gsf:template match='documentNode'>
+  <td><gsf:link><gsf:metadata name='Keyword'/></gsf:link></td>
+</gsf:template>
+\end{verbatim}\end{gsc}
+
+Table~\ref{tab:gsf-format} shows the set of \gst{'gsf'} (Greenstone Format) elements. If you have come from a \gsii\  background, Appendix~\ref{app:gs2format} shows \gsii\  format elements and their equivalents in \gsiii\ .
+ 
+\begin{table}
+\caption{Format elements for GSF format language}
+\label{tab:gsf-format}
+{\footnotesize
+\begin{tabular}{p{6.5cm}p{6.5cm}}
+\hline
+\bf Element       & \bf Description \\
+\hline
+\gst{<gsf:text/>} & The document's text\\
+\hline
+\gst{<gsf:link>...</gsf:link>} & The HTML link to the document itself \\
+\gst{<gsf:link type='document'>...
+</gsf:link>} & Same as above\\
+\gst{<gsf:link type='classifier'>...
+</gsf:link>} & A link to a classification node (use in classifierNode templates)\\
+\gst{<gsf:link type='source'>...
+</gsf:link>} & The HTML link to the original file---set for documents that have been converted from e.g. Word, PDF, PS \\
+\hline
+\gst{<gsf:icon/>}  & An appropriate icon\\
+\gst{<gsf:icon type='document'/>} & same as above\\
+\gst{<gsf:icon type='classifier'/>} & bookshelf icon for classification nodes\\
+\gst{<gsf:icon type='source'/>} & An appropriate icon for the original file e.g. Word, PDF icon\\
+\hline
+\gst{<gsf:metadata name='Title'/>} & The value of a metadata element for the current document or section, in this case, Title\\
+\gst{<gsf:metadata name='Title' select='select-type' [separator='y' multiple='true']/>} & A more extended selection of metadata values. The select field can be one of those shown in Table~\ref{tab:gsf-select-types}. There are two optional attributes: separator gives a String that will be used to separate the fields, default is ``, ``, and if multiple is set to true, looks for multiple values at each section.\\
+\gst{<gsf:metadata name='Date' format='formatDate'/>} & The value of a metadata element for the current document, formatted in some way. Current formatting options available are formatDate: turns '20040201' into '01 February 2004', and formatLanguage: turns 'en' into 'English', both in a language dependent manner. \\
+\hline
+\gst{<gsf:choose-metadata>
+  <gsf:metadata name='metaA'/>
+  <gsf:metadata name='metaB'/>
+  <gsf:metadata name='metaC'/>
+</gsf:choose-metadata>}
+ & A choice of metadata. Will select the first existing one. the metadata elements can have the select, separator and multiple attributes like normal.\\
+\hline
+\gst{<gsf:switch preprocess=
+'preprocess-type'>
+<gsf:metadata name='Title'/> 
+<gsf:when test='test-type'
+test-value='xxx'>...</gsf:when>
+<gsf:when test='test-type' 
+test-value='yyy'>...</gsf:when>
+<gsf:otherwise>...</gsf:otherwise>
+</gsf:switch>} & switch on the value of a particular metadata - the metadata is specified in gsf:metadata, has the same attributes as normal.\\
+\hline
+\end{tabular}}
+\end{table}
+
+The \gst{<gsf:metadata>} elements are used to output metadata values. The simplest case is \gst{<gsf:metadata name='Title'/>}---this outputs the Title metadata for the current document or section. Namespaces are important here: if the Title metadata is in the Dublin Core (dc) namespace, then the element should look like \gst{<gsf:metadata name='dc.Title'/>}. There are three other attributes for this element. The attribute \gst{multiple} is used when there may be more than one value for the selected metadata. 
+For instance, one document may fall into several classification categories, and therefore may have multiple Subject metadata values. Adding \gst{multiple='true'} to the \gst{<gsf:metadata>} element will retrieve all values, not just the first one. Multiple values are separated by commas by default. The \gst{separator} attribute is used to change the separating string. For example, adding \gst{separator=':~'} to the element will separate all values by a colon and a space.
+
+Sometimes you may want to display metadata values for sections other than the current one. For example, in the mgppdemo collection, in a search list we display the Titles of all the enclosing sections, followed by the Title of the current section, all separated by semi-colons. The display ends up looking something like:
+\emph{Farming snails 2; Starting out; Selecting your snails}
+where \emph{Selecting your snails} is the Title of the section in the results list, and \emph{Farming snails 2} and \emph{Starting out} are the Titles of the enclosing sections. The \gst{select} attribute is used to display metadata for sections other than the current one. Table~\ref{tab:gsf-select-types} shows the options available for this attribute. The \gst{separator} attribute is used here also, to specify the separating text.
+
+To get the previous metadata, the format statement would have the following in it:
+
+\begin{gsc}
+\begin{verbatim}
+<gsf:metadata name='Title' select='ancestors' separator='; '/>; 
+    <gsf:metadata name='Title'/>
+\end{verbatim}
+\end{gsc}
+
+\begin{table}
+\caption{Select types for metadata format elements}
+\label{tab:gsf-select-types}
+{\footnotesize
+\begin{tabular}{ll}
+\hline
+\bf Select Type & \bf Description\\
+\hline
+current & The current section \\
+parent & The immediate parent section\\
+ancestors & All the parents back to the root (topmost) section\\
+root & The root or topmost section \\
+siblings & All the sibling sections\\
+children & The immediate child sections of the current section\\
+descendents & All the descendent sections\\
+\hline
+\end{tabular}}
+\end{table}
+
+The \gst{<gsf:choose-metadata>} element selects the first available metadata value from the list of options. 
+\begin{gsc}
+\begin{verbatim}
+<gsf:choose-metadata>
+  <gsf:metadata name='dc.Title'/>
+  <gsf:metadata name='dls.Title'/>
+  <gsf:metadata name='Title'/>
+</gsf:choose-metadata>
+\end{verbatim}
+\end{gsc}
+
+This will display dls.Title if available, otherwise it will use dc.Title if available, otherwise it will use the Title metadata. If there are no values for any of these metadata elements, then nothing will be displayed.
+
+The \gst{<gsf:switch>} element allows different formatting depending on the value of a specified metadata element. For example, the following switch statement could be used to display a different icon for each document in a list depending on which organization it came from. 
+
+\begin{gsc}
+\begin{verbatim}
+<gsf:switch  preprocess='toLower;stripSpace'>
+  <gsf:metadata name='Organization'/>
+  <gsf:when test='equals' test-value='bostid'>
+     <!-- output BOSTID image --></gsf:when>
+  <gsf:when test='equals' test-value='worldbank'>
+     <!-- output world bank image --></gsf:when>
+  <gsf:otherwise><!-- output default image--></gsf:otherwise>
+</gsf:switch>
+\end{verbatim}
+\end{gsc}
+
+Preprocessing of the metadata value is optional. The preprocess types are \gst{toLower} (make the value lowercase), \gst{toUpper} (make the value uppercase), \gst{stripSpace} (removes any whitespace from the value). These operations are carried out on the value of the selected metadata before the test is carried out. Multiple processing types can be specified, separated by ; and they will be applied in the order specified (from left to right).
+
+Each option specifies a test and a test value. Test values are just text. Tests include \gst{startsWith}, \gst{contains}, \gst{exists}, \gst{equals}, \gst{endsWith}. Exists doesn't need a test value. Having an otherwise option ensures that something will be displayed even when none of the tests match.
+
+If none of the gsf elements meets your needs for formatting, XSLT can be entered directly into the format element, giving the collection designer full flexibility over how the collection appears. 
+
+The collection specific templates are added into the configuration file \gst{collectionConfig.xml}. Any templates found in the XSLT files can be overridden.
+The important part to adding templates into the configuration file is determining where to put them. Formatting templates cannot go just anywhere---there are standard places for them. Figure~\ref{fig:format-places} shows the positions that templates can occur.
+
+\begin{figure}
+\begin{gsc}\begin{verbatim}
+<collectionConfig>
+  <metadataList/>
+  <displayItemList/>
+  <search>
+    <format> <!--Put here templates related to searching and 
+        the query page. The common one is the documentNode 
+        template -->
+      <gsf:template match='documentNode'>...</gsf:template>
+    </format>
+  </search>
+  <browse>
+    <classifier name='xx'>
+      <format><!-- put here templates related to formating a 
+        particular classifier page. Common ones are documentNode 
+        and classifierNode templates-->
+        <gsf:template match='documentNode'>...</gsf:template>
+        <gsf:template match='classifierNode'>...</gsf:template>
+        <gsf:template match='classifierNode' mode='horizontal'>...
+          </gsf:template>
+      </format>
+    </classifier>
+    <classifier>...</classifier>
+    <format><!-- formatting for all the classifiers. these will
+      be overridden by any classifier specific formatting 
+      instructions --></format>
+  </browse>
+  <display>
+    <format><!-- here goes any formatting relating to the display 
+        of the documents. These are generally named templates, 
+        and format options -->
+      <gsf:template name='documentContent'>...</gsf:template>
+      <gsf:option name='TOC' value='true'/>
+    </format>
+  </display>
+</collectionConfig>
+\end{verbatim}\end{gsc}
+\caption{Places for format statements}
+\label{fig:format-places}
+\end{figure} 
+
+ 
+There are also formatting instructions that are not templates but are options. 
+These are described in Table~\ref{tab:format_options}. They are entered into the configuration file like \gst{<gsf:option name='coverImages' value='false'/>}
+
+\begin{table}
+\caption{Formatting options}
+\label{tab:format_options}
+{\footnotesize
+\begin{tabular}{llp{5cm}}
+\hline
+\bf option name & \bf values & \bf description \\
+\hline
+coverImages & true, false & whether or not to display cover images for documents \\
+documentTOC & true, false & whether or not to display the table of contents for the document\\
+\hline
+\end{tabular}}
+\end{table}
+
+Note, format templates are added into the XSLT files before transforming, while the options are added into the page source, and used in tests in the XSLT.
+
+\subsubsection{Changing the service text strings}
+
+Each collection has a set of services which are the access points for the information in the collection. Each service has a set of text strings which are used to display it. These include name, description, the text on the submit button, and names and descriptions of all the parameters to the service.
+
+These text strings are found in \gst{.properties} files, in \gst{\$GSDL3HOME/WEB-INF/classes}. The names of the files are based on class names. Subclasses can define their own properties, or can use their parent class ones. For example, \gst{AbstractSearch} defines strings for the \gst{TextQuery} service, in \gst{AbstractSearch.properties}. \gst{GS2MGSearch} just uses these default ones, so doesn't need its own properties file.
+
+A particular collection can override the properties for any service. For example, if a collection uses the \gst{GS2MGSearch} service rack (look in the \gst{buildConfig.xml} file for a list of service racks used), and the collection builder wants to change the text associated with this service, they can put a \gst{GS2MGSearch.properties} file in the resources directory of the collection. After a reconfigure of the collection, this will be used in preference to the one in the default resources directory.
+
+\subsection{Customizing the interface}\label{sec:interface-customise}
+
+Format statements in the collection configuration files provide a way to change small parts of the collection display. For large scale customizations to a collection, or ones that apply to a site as a whole, a second mechanism is available. The interface is defined by a set of XSLT files that transform the page data into HTML. Any of these files can be overridden to provide specialized display, on a site or collection basis. 
+
+The first section looks at customizing the existing interface, while the second section looks at defining a whole new interface. The last section describes how to add a new language translation of an interface.
+
+\subsubsection{Modifying an existing interface}
+
+Most of an interface is defined by XSLT files, which are stored in \gst{\$GSDL3HOME/\-interfaces/\-interface-name/\-transform}. These can be changed and the changes will take effect straight away. If changes only apply to certain collections or sites, not everything that uses the interface, you can override some of the files by putting new ones in a different place. XSLT files are looked for in the following  order: collection, site, interface, default interface. (This currently only apples to sites, and therefore collections, that reside in the same \gs\  installation as the interface.) 
+
+Sites and collections can have a transform directory, which is where customized XSLT files should go. Any XSLT files in here will be used in preference to the interface files when using this collection. For example, if you want to have a completely different layout for the about page of a collection, you can put a new \gst{about.xsl} file into the collection's \gst{transform} directory, and this will be used instead. This is what we do for the Gutenberg sample collection.
+
+This also applies to files that are included from other XSLT files. For example the \gst{query.xsl} for the query pages includes a file called \gst{querytools.xsl}. To have a particular site show a different query interface either of these files may need to be modified. Creating a new version of either of these and putting it in the site \gst{transform} directory will work. Either the new \gst{query.xsl} will include the default \gst{querytools.xsl}, or the default \gst{query.xsl} will include the new \gst{querytools.xsl}. The \gst{xsl:include} directives are preprocessed by the Java code and full paths added based on availability of the files, so that the correct one is used.
+
+Note that you cannot include a file with the same name as the including file. For example \gst{query.xsl} cannot include \gst{query.xsl} (it is tempting to want to do this if you just want to change one template for a particular file, and then include the default. but you cant).
+
+You can add the argument \gst{o=xml} to any URL and you wil be returned the XML before transformation by a stylesheet. This shows you the XML page source. It can be useful when you are trying to write some new XSLT statements.
+
+\subsubsection{Defining a new interface}
+
+A new interface may be needed if different instantiations of the library require different interfaces, or different developers want their own look and feel. Creating a new interface will allow modifications to be made while leaving the original one intact. 
+
+A new interface needs a directory in \gst{\$GSDL3HOME/interfaces}, the name of this directory becomes the interface name. Inside, it needs \gst{images} and \gst{transform} directories,  and an \gst{interfaceConfig.xml} file. The \gst{interfaceConfig.xml} file may specify a base interface, in which case the new interface only needs to define XSLT for the parts that are different. Otherwise, it will need a full set of XSLT files. 
+
+To use a new interface, the \gst{\$GSDL3HOME/WEB-INF/web.xml} file must be edited: either change the interface that a current servlet instance is using, or add another servlet instantiation to the file (see Section~\ref{sec:sites-and-ints} or Appendix~\ref{app:tomcat}). The Tomcat server must be restarted for this to take effect.
+
+\subsubsection{Changing the interface language}\label{sec:interface-language}
+
+The interface language can be changed by going to the preferences page, and choosing a language from the list, which includes all languages into which the interface has been translated.
+
+It is easy to add a new interface language to \gs\ .  Language specific text strings are separated out from the rest of the system to allow for easy incorporation of new languages. These text strings are contained in Java resource bundle properties files. These are plain text files consisting of key-value pairs, located in \gst{\$GSDL3HOME/WEB-INF/classes}. Each interface has one named \gst{interface\_name.properties} (where \gst{'name'} is the interface name, for example, \gst{interface\_default.properties}, or \gst{interface\_classic.properties}). Each service class has one with the same name as the class (e.g. \gst{GS2Search.properties}). To add another language all of the base \gst{.properties}  files must be translated. The translated files keep the same names, but with a language extension added. For example, a French version of \gst{interface\_default.properties} would be named \gst{interface\_default\_fr.properties}.
+
+Keys will be looked up in the properties file closest to the specified language. For example, if language \gst{fr\_CA} was specified (French language, country Canada), and the default locale was \gst{en\_GB},  Java would look at properties files in the following order, until it found the key: \gst{XXX\_fr\_CA.properties}, \gst{XXX\_fr.properties},  \gst{XXX\_en\_GB.properties}, then \gst{XXX\_en.properties}, and finally the default \gst{XXX.properties}.
+
+These new files are available straight away---to use the new language, add e.g. \gst{l=fr} to the arguments in the URL. To get \gs\ to add it in to the list of languages on the preferences page, an entry needs to be added into the languages list in the \gst{interfaceConfig.xml} file (see Section~\ref{sec:interfaceconfig}). Modification of this file requires a restart of the Tomcat server for the changes to be recognized.
+
+\newpage 
+\section{Developing \gsiii : Run-time system}\label{sec:develop-runtime}
+
+[TODO: rewrite this section\\
+runtime object structure diagram. describe the modules.\\ 
+class hierarchy,\\
+directory structure and where everything lives\\
+message format.\\
+overall description of message passing sequence.\\
+configuration process - start up and runtime\\
+\\
+page generation\\
+]
+\subsection{Overview of modules??}
+
+A \gsiii\  'library' system consists of many components: MessageRouter, Receptionist, Actions, Collections, ServiceRacks etc.  Figure~\ref{fig:local} shows how they fit together in a stand-alone system. The top left part is concerned with displaying the data, while the bottom right part is the collection data serving part. The two sides communicate through the MessageRouter. There is a one-to-one correspondence between modules and Java classes, with the exception of services: for coding and/or run-time efficiency reasons, several Service modules may be grouped together into one ServiceRack class.
+
+\begin{figure}[t]
+  \centering
+  \includegraphics[width=4in]{local} %5.8
+  \caption{A simple stand-alone site.}
+  \label{fig:local}
+\end{figure}
+
+
+{\em MessageRouter}: this is the central module for a site. It controls the site, loading up all the collections, clusters, communicators needed. All messages pass through the MessageRouter. Communication between remote sites is always done between MessageRouters, one for each site.
+
+{\em Collection and ServiceCluster}: these are very similar, and group a set of services into a conceptual group.. They both provide some metadata about the collection/cluster, and a list of services. The services are provided by ServiceRack objects that the collection/cluster loads up. A Collection is a specific type of ServiceCluster. A ServiceCluster groups services that are related conceptually, e.g. all the building services may be part of a cluster. What is part of a cluster is specified by the site configuration file. A Collection's services are grouped by the fact that they all operate on some common data---the documents in the collection.
+Functionally Collection and ServiceCluster are very similar, but conceptually, and to the user, they are quite different.
+
+{\em Service}: these provide the core functionality of the system e.g. searching, retrieving documents, building collections etc. One or more may be grouped into a single Java class (ServiceRack) for code reuse, or to avoid instantiating the same objects several times. For example, MGPP searching services all need to have the index loaded into memory. 
+
+{\em Communicator/Server}: these facilitate communication between remote modules. For example, if you want MR1 to talk to MR2, you need a Communicator-Server pair. The Server sits on top of MR2, and MR1 talks to the Communicator. Each communication type needs a new pair. So far we have only been using SOAP, so we have a SOAPCommunicator and a SOAPServer.
+
+{\em Receptionist}: this is the point of contact for the 'front end'. Its core functionality involves routing requests to the Actions, but it may do more than that. For example, a Receptionist may: modify the request in some way before sending it to the appropriate Action; add some data to the page responses that is common to all pages; transform the response into another form using XSLT. There is a hierarchy of different Receptionist types, which is described in Section~\ref{sec:recepts}.
+
+{\em Actions}: these do the job of creating the 'pages'. There is a different action for each type of page, for example PageAction handles semi-static pages, QueryAction handles queries, DocumentAction displays documents. They know a little bit about specific service types. Based on the 'CGI' arguments passed in to them, they construct requests for the system, and put together the responses into data for the page. This data is returned to the Receptionist, which may transform it to HTML. The various actions are described in  more detail in Section~\ref{sec:pagegen}.
+
+
+\subsection{Start up configuration}\label{sec:startup-config}
+
+We use the Tomcat web server, which operates either stand-alone in a test mode
+or in conjunction with the Apache web server.  The \gs\  LibraryServlet
+class is loaded by Tomcat  and the servlet's \gst{init()} method is called.  Each time a
+\gst{get/put/post} (etc.) is used, a new thread is started and
+\gst{doGet()/doPut()/doPost()} (etc.) is called.
+
+The \gst{init()} method creates a new Receptionist and a new 
+MessageRouter. Default classes (DefaultReceptionist, MessageRouter) are used unless subclasses have been specified  in the servlet initiation parameters (see Section~\ref{sec:sites-and-ints}). The appropriate system variables are set for each object (interface
+name, site name, etc.) and then \gst{configure()} is called on both. The MessageRouter handle 
+is passed to the Receptionist. The servlet then communicates only with
+the Receptionist, not with the MessageRouter.
+
+The Receptionist reads in the \gst{interfaceConfig.xml} file (see Section~\ref{sec:interfaceconfig}), and loads up all the different Action classes. Other Actions may be loaded on the fly as needed. Actions are added to a map, with shortnames for keys. Eg the QueryAction is added with key 'q'. The Actions are passed the MessageRouter reference too.
+If the Receptionist is a TransformingReceptionist, a mapping between shortnames  and XSLT file names is also created. 
+
+The MessageRouter reads in its site configuration file \gst{siteConfig.xml} (see Section~\ref{sec:siteconfig}). It creates a module map that maps names to objects. This is used for routing the messages. It also keeps small chunks of XML---serviceList, collectionList, clusterList and siteList. These are part of what get returned in response to a describe request (see Section~\ref{sec:describe}.).
+
+Each ServiceRack specified in the configuration file is created, then queried for its list of services. Each service name is added to the map, pointing to the ServiceRack object. Each service is also added to the serviceList. After this stage, ServiceRacks are transparent to the system, and each service is treated as a separate module.
+
+ServiceClusters are created and passed the \gst{<serviceCluster>} element for configuration. They are added to the map as is, with the cluster name as a key. A serviceCluster is also added to the serviceClusterList.
+
+For each site specified, the MessageRouter creates an appropriate type of Communicator object. Then it tries to get the site description. If the server for the remote site is up and running, this should  be successful. The site will be added to the mapping with its site name as a key. The site's collections, services and clusters will also be added into the static xml lists. If the server for the remote site is not running, the site will not be included in the siteList or module map. To try again to access the site, either Tomcat must be restarted, or a run-time reconfigure-site command must be sent (see Section~\ref{sec:runtime-config}).
+
+The MessageRouter also looks inside the site's \gst{collect} directory, and  loads up a Collection object for each valid collection found. If a \gst{collectionInit.xml} file is present, a subclass of Collection may be used.
+The Collection object reads its \gst{buildConfig.xml} and \gst{collectionConfig.xml}
+files, determines the metadata, and loads ServiceRack classes based on the 
+names specified in \gst{buildConfig.xml\/}. The \gst{<serviceRack>} XML element is passed to the object to be used in configuration. The \gst{collectionConfig.xml} contents are also passed in to the ServiceRacks. Any format or display information that the services need must be extracted from the collection configuration file.
+Collection objects are added to the module map with their name as a key, and also a collection element is added into the collectionList XML.
+
+\subsection{Message passing}
+
+There are two types of messages used by the system: external and internal messages. All messages have an enclosing \gst{<message>} element, which contains either one or more requests, or one or more responses. In the following descriptions, the message element is not shown, but is assumed to be present.  
+Action in \gsiii\  is originated by a request coming in from the outside. In the standard web-based \gs, this comes from a servlet and is passed into the Receptionist. This ``external'' type request is a request for a page of data, and contains a representation of the CGI style arguments. A page of XML is returned, which can be in HTML format or other depending on the output parameter of the request. 
+
+Messages inside the system (``internal'' messages) all follow the same basic format: message elements contain multiple request elements, or multiple response elements. Messaging is all synchronous. The same number of responses as requests will be returned. Currently all requests are independent, so any requests can be combined into the same message, and they will be answered separately, with their responses being sent back in a single message.
+
+When a page request (external request) comes in to the Receptionist, it looks at the action attribute and passes the request to the appropriate Action module. The Action will fire one or more internal requests to the MessageRouter, based on the arguments. The data is gathered into a  response, which is returned to the Receptionist.  The page that the receptionist returns contains the original request, the response from the action and other info as needed (depends on the type of Receptionist). The data may be transformed in some way --- for the \gs\ servlet  we transform using XSLT to generate HTML pages.
+
+Actions send internal style messages to the MessageRouter. Some can be answered by it, others are passed on to collections, and maybe on to services. Internal requests are for simple actions, such as search, retrieve metadata, retrieve document text
+There are different internal request types: describe, process, system, format, status. Process requests do the actual work of the system, while the other types get auxiliary information. The format of the requests and responses for each internal request type are described in the following sections. External style requests, and their page responses are described in the Section about page generation (Section~\ref{sec:pagegen}).
+
+\subsection{'describe'-type messages}\label{sec:describe}
+
+The most basic of the internal standard requests is ``describe-yourself'', which can be sent to any module in the system. The module responds with a semi-predefined piece of XML, making these requests very efficient. The response is predefined apart from any language-specific text strings, which are put together as each request comes in, based on the language attribute of the request.
+\begin{quote}\begin{gsc}\begin{verbatim}
+<request lang='en' type='describe' to=''/>
+\end{verbatim}\end{gsc}\end{quote}
+If the \gst{to} field is empty, a request is answered by the MessageRouter. 
+An example response from a MessageRouter might look like this:
+\begin{quote}\begin{gsc}\begin{verbatim}
+<response lang='en' type='describe'>
+  <serviceList/>
+  <siteList>
+    <site name='org.greenstone.gsdl1'
+            address='http://localhost:8080/greenstone3/services/localsite'
+            type='soap' />
+  </siteList>
+  <serviceClusterList>
+    <serviceCluster name="build" />
+  </serviceClusterList>
+  <collectionList>
+    <collection name='org.greenstone.gsdl1/
+  	              org.greenstone.gsdl2/fao' />
+    <collection name='org.greenstone.gsdl1/demo' />
+    <collection name='org.greenstone.gsdl1/fao' />
+    <collection name='myfiles' />
+  </collectionList>
+</response>
+\end{verbatim}\end{gsc}\end{quote}
+This MessageRouter has no individual site-wide services (an empty \gst{<serviceList>}), but has a service cluster called build (which provides collection importing and building functionality).  It
+communicates with one site, \gst{org.greenstone.gsdl1}.  It is aware of four
+collections.  One of these, \gst{myfiles}, belongs to it; the other three are
+available through the external site.  One of those collections is actually from
+a further external site.
+
+It is possible to ask just for a specific part of the information provided by a
+describe request, rather than the whole thing. For example, these two
+messages get the \gst{collectionList} and the \gst{siteList} respectively: 
+\begin{quote}\begin{gsc}\begin{verbatim}
+<request lang='en' type='describe' to=''>
+  <paramList>
+    <param name='subset' value='collectionList'/>
+  </paramList>
+</request>
+
+<request lang='en' type='describe' to=''>
+  <paramList>
+    <param name='subset' value='siteList'/>
+  </paramList>
+</request>
+\end{verbatim}\end{gsc}\end{quote}
+
+Subset options for the MessageRouter include \gst{collectionList}, \gst{serviceClusterList}, \gst{serviceList}, \gst{siteList}.
+
+When a collection or service cluster is asked to describe itself, what is returned is a list of metadata, some display elements, and  a list of services.  For example, here is such a message, along with a sample response.
+
+\begin{quote}\begin{gsc}\begin{verbatim}
+<request lang='en' type='describe' to='mgppdemo'/>
+
+<response from="mgppdemo" type="describe">
+  <collection name="mgppdemo">
+    <displayItem lang="en" name="name">greenstone mgpp demo
+    </displayItem>
+    <displayItem lang="en" name="description">This is a 
+      demonstration collection for the Greenstone digital 
+      library software. It contains a small subset (11 books) 
+      of the Humanity Development Library. It is built with 
+      mgpp.</displayItem>
+    <displayItem lang="en" name="icon">mgppdemo.gif</displayItem>
+    <serviceList>
+      <service name="DocumentStructureRetrieve" type="retrieve" />
+      <service name="DocumentMetadataRetrieve" type="retrieve" />
+      <service name="DocumentContentRetrieve" type="retrieve" />
+      <service name="ClassifierBrowse" type="browse" />
+      <service name="ClassifierBrowseMetadataRetrieve" 
+            type="retrieve" />
+      <service name="TextQuery" type="query" />
+      <service name="FieldQuery" type="query" />
+      <service name="AdvancedFieldQuery" type="query" />
+      <service name="PhindApplet" type="applet" />
+    </serviceList>
+    <metadataList>
+      <metadata name="creator">greenstone@cs.waikato.ac.nz</metadata>
+      <metadata name="numDocs">11</metadata>  
+      <metadata name="buildType">mgpp</metadata>
+      <metadata name="httpPath">http://kanuka:8090/greenstone3/sites/
+                                localsite/collect/mgppdemo</metadata>
+    </metadataList>
+  </collection>
+</response>
+\end{verbatim}\end{gsc}\end{quote}
+
+Subset options for a collection or serviceCluster include \gst{metadataList}, \gst{serviceList}, and \gst{displayItemList}.
+
+This collection provides many typical services. Notice how this response lists the services available, while the collection configuration file for this collection (Figure~\ref{fig:collconfig}) described serviceRacks. Once the service racks have been configured, they become transparent in the system, and only services are referred to.
+There are three document retrieval services, for structural information, metadata, and content. The Classifier services retrieve classification structure and metadata. These five services were all provided by the GS2MGPPRetrieve ServiceRack. The three query services were provided by GS2MGPPSearch serviceRack, and provide different kinds of query interface. The last service, PhindApplet, is provided by the PhindPhraseBrowse serviceRack and is an applet service.
+
+A \gst{describe} request sent to a service returns a list of parameters that
+the service accepts and some display information, (and in future may describe the content type for the request and response). Subset options for the request include \gst{paramList} and \gst{displayItemList}.
+
+Parameters can be in the following formats:
+\begin{quote}\begin{gsc}\begin{verbatim}
+<param name='xxx' type='integer|boolean|string|invisible' default='yyy'/>
+<param name='xxx' type='enum_single|enum_multi' default='aa'/>
+  <option name='aa'/><option name='bb'/>...
+</param>
+<param name='xxx' type='multi' occurs='4'>
+ <param .../>
+ <param .../>
+</param>
+\end{verbatim}\end{gsc}\end{quote}
+
+If no default is specified, the parameter is assumed to be mandatory.
+Here are some examples of parameters:
+\begin{quote}\begin{gsc}\begin{verbatim}
+<param name='case' type='boolean' default='0'/>
+
+<param name='maxDocs' type='integer' default='50'/>
+
+<param name='index' type='enum' default='dtx'>
+  <option name='dtx'/>
+  <option name='stt'/>
+  <option name='stx'/>
+<param>
+
+<!-- this one is for the text box and field list for the 
+simple field query-->
+<param name='simpleField' type='multi' occurs='4'>
+  <param name='fqv' type='string'/>
+  <param name='fqf' type='enum_single'>
+    <option name='TI'/><option name='AU'/><option name='OR'/>
+  </param>
+</param>
+
+\end{verbatim}\end{gsc}\end{quote}
+The type attribute is used to determine how to display the parameters on a web page or interface. For example, a string parameter may result in a text entry box, a boolean an on/off button, enum\_single/enum\_multi a drop-down menu, where one or many items, respectively, can be selected.
+A multi-type parameter indicates that two or more parameters are associated, and should be displayed appropriately. For example, in a field query, the text box and field list should be associated. The occurs attribute specifies how many times the parameter should be displayed on the page.
+Parameters also come with display information: all the text strings needed to present them to the user. These include the name of the parameter and the display values for any options. These are included in the above parameter descriptions in the form of \gst{<displayItem>} elements.
+
+A service description also contains some display information---this includes the name of the service, and the text  for the submit button. 
+
+Here is a sample describe request to the FieldQuery service of collection mgppdemo, along with its response. The parameters in this example include their display information. Figure~\ref{fig:query-display} shows an example HTML search form that may be generated from this describe response. 
+
+\begin{quote}\begin{gsc}\begin{verbatim}
+<request lang="en" to="mgppdemo/FieldQuery" type="describe" />
+
+<response from="mgppdemo/FieldQuery" type="describe">
+  <service name="FieldQuery" type="query">
+    <displayItem name="name">Form Query</displayItem>
+    <displayItem name="submit">Search</displayItem>
+    <paramList>
+      <param default="Doc" name="level" type="enum_single">
+        <displayItem name="name">Granularity to search at</displayItem>
+        <option name="Doc">
+          <displayItem name="name">Document</displayItem>
+        </option>
+        <option name="Sec">
+          <displayItem name="name">Section</displayItem>
+        </option>
+        <option name="Para">
+          <displayItem name="name">Paragraph</displayItem>
+        </option>
+      </param>
+      <param default="1" name="case" type="boolean">
+        <displayItem name="name">Turn casefolding </displayItem>
+        <option name="0">
+          <displayItem name="name">off</displayItem>
+        </option>
+        <option name="1">
+          <displayItem name="name">on</displayItem>
+        </option>
+      </param>
+      <param default="1" name="stem" type="boolean">
+        <displayItem name="name">Turn stemming </displayItem>
+        <option name="0">
+          <displayItem name="name">off</displayItem>
+        </option>
+        <option name="1">
+          <displayItem name="name">on</displayItem>
+        </option>
+      </param>
+      <param default="10" name="maxDocs" type="integer">
+        <displayItem name="name">Maximum documents to return
+        </displayItem>
+      </param>
+      <param name="simpleField" occurs="4" type="multi">
+        <displayItem name="name"></displayItem>
+        <param name="fqv" type="string">
+          <displayItem name="name">Word or phrase </displayItem>
+        </param>
+        <param default="ZZ" name="fqf" type="enum_single">
+          <displayItem name="name">in field</displayItem>
+          <option name="ZZ">
+            <displayItem name="name">allfields</displayItem>
+          </option>	  
+          <option name="TX">
+            <displayItem name="name">text</displayItem>
+          </option>
+          <option name="TI">
+            <displayItem name="name">Title</displayItem>
+          </option>
+          <option name="SU">
+            <displayItem name="name">Subject</displayItem>
+          </option>
+          <option name="ORG">
+            <displayItem name="name">Organization</displayItem>
+          </option>
+          <option name="SO">
+            <displayItem name="name">Source</displayItem>
+          </option>
+        </param>
+      </param>
+    </paramList>
+  </service>
+</response>
+\end{verbatim}\end{gsc}\end{quote}
+
+\begin{figure}[t]
+  \centering
+  \includegraphics[width=3.5in]{query2.ps}
+  \caption{The previous query service describe response as displayed on the search page.}
+  \label{fig:query-display}
+\end{figure}
+
+A describe request to an applet type service returns the applet HTML element: this will be embedded into a web page to run the applet. 
+\begin{quote}\begin{gsc}\begin{verbatim}
+<request type='describe' to='mgppdemo/PhindApplet'/>
+
+<response type='describe'>
+  <service name='PhindApplet' type='query'>
+    <applet ARCHIVE='phind.jar, xercesImpl.jar, gsdl3.jar, 
+			jaxp.jar, xml-apis.jar'
+            CODE='org.greenstone.applet.phind.Phind.class'
+            CODEBASE='lib/java'
+            HEIGHT='400' WIDTH='500'>
+      <PARAM NAME='library' VALUE=''/>
+      <PARAM NAME='phindcgi' VALUE='?a=a&amp;sa=r&amp;sn=Phind'/>
+      <PARAM NAME='collection' VALUE='mgppdemo' />
+      <PARAM NAME='classifier' VALUE='1' />
+      <PARAM NAME='orientation' VALUE='vertical' />
+      <PARAM NAME='depth' VALUE='2' />
+      <PARAM NAME='resultorder' VALUE='L,l,E,e,D,d' />
+      <PARAM NAME='backdrop' VALUE='interfaces/default/>
+				      images/phindbg1.jpg'/>
+      <PARAM NAME='fontsize' VALUE='10' />
+      <PARAM NAME='blocksize' VALUE='10' />
+      The Phind java applet.
+    </applet>
+    <displayItem name="name">Browse phrase hierarchies</displayItem>
+  </service>
+</response>
+\end{verbatim}\end{gsc}\end{quote}
+
+Note that the library parameter has been left blank. This is because library refers to the current servlet that is running and the name is not necessarily known in advance. So either the applet action or the Receptionist must fill in this parameter before displaying the HTML.
+
+\subsection{'system'-type messages}\label{sec:system}
+
+``System'' requests are used to tell a MessageRouter, Collection or ServiceCluster to update its cached information and activate or deactivate other modules. For example, the MessageRouter has a set of Collection modules that it can talk to. It also holds some XML information about those collections---this is returned when a request for a collection list comes in. If a collection is deleted or modified, or a new one created, this information may need to change, and the list of available modules may also change. Currently these requests are initiated by particular CGI requests (see Section~\ref{sec:runtime-config}).
+
+The basic format of a system request is as follows:
+
+\begin{quote}\begin{gsc}\begin{verbatim}
+<request type='system' to=''>
+  <system .../>
+</request>
+\end{verbatim}\end{gsc}\end{quote}
+
+One or more actual requests are specified in  system elements. The following are examples:
+\begin{quote}\begin{gsc}\begin{verbatim}
+<system type='configure' subset=''/>
+<system type='configure' subset='collectionList'/>
+<system type='activate' moduleType='collection' moduleName='demo'/>
+<system type='deactivate' moduleType='site' moduleName='site1'/>
+\end{verbatim}\end{gsc}\end{quote}
+
+The first request reconfigures the whole site---the MessageRouter goes through its whole configure process again. The second request just reconfigures the collectionList---the MessageRouter will delete all its collection information, and re-look through the collect directory and reload all the collections again.
+The third request is to activate collection demo. This could be a new collection, or a reactivation of an old one. If a collection module already exists, it will be deleted, and a new one loaded. The final request deactivates the site site1---this removes the site from the siteList and module map, and also removes any of that sites collections/services from the static lists.
+
+A response just contains a status message\footnote{TODO: add in error/status codes}, for example:
+\begin{quote}\begin{gsc}\begin{verbatim}
+<status>MessageRouter reconfigured successfully</status>
+<status>Error on reconfiguring collectionList</status>
+<status>collection:demo activated</status>
+<status>site:site1 deactivated</status>
+\end{verbatim}\end{gsc}\end{quote}
+
+System requests are mainly answered by the MessageRouter. However, Collections and ServiceClusters will respond to a subset of these requests. 
+
+\subsection{'format'-type messages}\label{sec:format}
+
+Collection designers are able to specify how their collection looks to a certain degree. They can specify format statements for display that will apply to the results of a search, the display of a document, entries in a classification hierarchy, for example. This info is generally service specific. All services respond to a format request, where they return any service specific formatting information. A typical request and response looks like this:
+\begin{quote}\begin{gsc}\begin{verbatim}
+<request lang="en" to="mgppdemo/FieldQuery" type="format" />
+
+<response from="mgppdemo/FieldQuery" type="format">
+  <format>
+    <gsf:template match="documentNode"><td><gsf:link>
+      <gsf:metadata name="Title" />(<gsf:metadata name="Source" />)
+      </gsf:link></td>
+    </gsf:template>
+  </format>
+</response>
+\end{verbatim}\end{gsc}\end{quote}
+
+The actual format statements are described in Section~\ref{sec:formatstmt}. They are templates written directly in XSLT, or in GSF (GreenStone Format) which is a simple XML representation of the more complicated XSLT templates. 
+GSF-style format statements need to be converted to proper XSLT. This is currently done by the Receptionist (but may be moved to an ActionHelper): the format XML is transformed to XSLT using XSLT with the config\_format.xsl stylesheet.
+
+\subsection{'status'-type messages}\label{sec:status}
+
+These are only used with process-type services, which are those where a request is sent to start some type of process (see Section~\ref{sec:process}). An initial 'process' request to a 'process' service generates a response which states whether the process had successfully started, and whether its still continuing. If the process is not finished, status requests can be sent repeatedly to the service to poll the status, using the pid to identify the  process.  Status codes are used to identify the state of a process. The values used at the moment are listed in Table~\ref{tab:status codes}\footnote{A more standard set of codes should probably be used, for example, the HTTP codes}.
+
+\begin{table}
+\caption{Status codes currently used in \gsiii\ }
+\label{tab:status codes}
+{\footnotesize
+\begin{tabular}{llp{8cm}}
+\hline
+\bf code name & \bf code  & \bf meaning \\
+& \bf value & \\
+\hline
+SUCCESS &  1 & the request was accepted, and the process was  completed \\
+ACCEPTED & 2 & the request was accepted, and the process has been started, but it is not completed yet \\
+ERROR & 3 & there was an error and the process was stopped \\
+CONTINUING & 10 & the process is still continuing \\
+COMPLETED & 11 & the process has  finished \\
+HALTED & 12 & the process has stopped  \\
+INFO & 20 & just an info message that doesn't imply anything \\
+\hline
+\end{tabular}}
+\end{table}
+
+ The following shows an example status request, along with two responses, the first a 'OK but continuing' response, and the second a 'successfully completed' response. The content of the status elements in the two responses is the output from the process since the last status update was sent back.
+
+\begin{quote}\begin{gsc}\begin{verbatim}
+<request lang="en" to="build/ImportCollection" type="status">
+  <paramList>
+    <param name="pid" value="2" />
+  </paramList>
+</request>
+
+<response from="build/ImportCollection">
+  <status code="2" pid="2">Collection construction: import collection.
+command = import.pl -collectdir /research/kjdon/home/greenstone3/web/sites/
+    localsite/collect test1
+starting
+  </status>
+</response>
+
+<response from="build/ImportCollection">
+  <status code="11" pid="2">RecPlug: getting directory 
+/research/kjdon/home/greenstone3/web/sites/localsite/collect/test1/import
+WARNING - no plugin could process /.keepme
+ 
+*********************************************
+Import Complete
+*********************************************
+* 1 document was considered for processing
+* 0 were processed and included in the collection
+* 1 was rejected. See /research/kjdon/home/greenstone3/web/sites/
+    localsite/collect/test1/etc/fail.log for a list of rejected documents
+Success
+  </status>
+</response>
+\end{verbatim}\end{gsc}\end{quote}
+
+\subsection{'process'-type messages}
+
+Process requests and responses  provide  the major functionality of the system---these are the ones that do the actual work. The format depends on the service they are for, so I'll describe these by service.
+
+Query type services TextQuery, FieldQuery, AdvancedFieldQuery (GS2MGSearch, GS2MGPPSearch), TextQuery (LuceneSearch)
+The main type of requests in the system are for services. There are different types of services, currently: \gst{query}, \gst{browse}, \gst{retrieve}, \gst{process}, \gst{applet}, \gst{enrich}. Query services do some kind of search and return a list of document identifiers. Retrieve services can return the content of those documents, metadata about the documents, or other resources. Browse is for browsing lists or hierarchies of documents. Process type services are those where the request is for a command to be run. A status code will be returned immediately, and then if the command has not finished, an update of the status can be requested. Applet services are those that run an applet. Enrich services take a document and return the document with some extra markup added.
+
+  Other possibilities include transform, extract, accrete. These types of service generally enhance the functionality of the first set. They may be used during collection formation: 'accrete' documents by adding them to a collection, 'transform' the documents into a different format, 'extract' information or acronyms from the documents, 'enrich' those documents with the information extracted or by adding new information. They may also be used during querying: 'transform' a query before using it to query a collection, or 'transform' the documents you get back into an appropriate form.
+
+The basic structure of a service 'process' request is as follows:
+\begin{quote}\begin{gsc}\begin{verbatim}
+
+<request lang='en'  type='process' to='demo/TextQuery'>
+  <paramList/>
+  other elements...
+</request>
+
+\end{verbatim}\end{gsc}\end{quote}
+
+The parameters are name-value pairs corresponding to parameters that were specified in the service description sent in response to a describe request. 
+
+\begin{quote}\begin{gsc}\begin{verbatim}
+<param name='case' value='1'/>
+<param name='maxDocs' value='34'/>
+<param name='index' value='dtx'/>
+\end{verbatim}\end{gsc}\end{quote}
+
+Some requests have other content---for document retrieval, this would be a list of document identifiers to retrieve. For metadata retrieval, the content is the list of documents to retrieve metadata for. 
+
+Responses vary depending on the type of request. The following sections look at the process type requests and responses for each type of service.
+
+\subsubsection{'query'-type services}
+Responses to query requests contain a list of document identifiers, along with some other information, dependent on the query type. For a text query, this includes term frequency information, and some metadata about the result. For instance, a text query on 'snail farming', with the parameter 'maxDocs=10' might return the first 10 documents, and one of the query metadata items would be the total number of documents that matched the query.\footnote{no metadata about the query result is returned yet.}
+
+The following shows an example query request and its response.
+
+Find at most 10 Sections in the mgppdemo collection, containing the word snail (stemmed), returning the results in ranked order:
+\begin{quote}\begin{gsc}\begin{verbatim}
+<request lang='en'  to="mgppdemo/TextQuery" type="process">
+  <paramList>
+    <param name="maxDocs" value="10"/>
+    <param name="queryLevel" value="Section"/>
+    <param name="stem" value="1"/>
+    <param name="matchMode" value="some"/>
+    <param name="sortBy" value="1"/>
+    <param name="index" value="t0"/>
+    <param name="case" value="0"/>
+    <param name="query" value="snail"/>
+  </paramList>
+</request>
+
+<response from="mgppdemo/TextQuery" type="process">
+  <metadataList>
+    <metadata name="numDocsMatched" value="59" />
+  </metadataList>
+  <documentNodeList>
+    <documentNode nodeID="HASHac0a04dd14571c60d7fbfd.4.2" 
+	docType='hierarchy' nodeType="leaf" />
+    <documentNode nodeID="HASH010f073f22033181e206d3b7.2.12" 
+	docType='hierarchy' nodeType="leaf" />
+    <documentNode nodeID="HASH010f073f22033181e206d3b7.1" 
+	docType='hierarchy' nodeType="interior" />
+    <documentNode nodeID="HASHac0a04dd14571c60d7fbfd.2.2" 
+	docType='hierarchy' nodeType="leaf" />
+    ...
+  </documentNodeList>
+  <termList>
+    <term field="" freq="454" name="snail" numDocsMatch="58" stem="3">
+      <equivTermList>
+        <term freq="" name="Snail" numDocsMatch="" />
+        <term freq="" name="snail" numDocsMatch="" />
+        <term freq="" name="Snails" numDocsMatch="" />
+        <term freq="" name="snails" numDocsMatch="" />
+      </equivTermList>
+    </term>
+  </termList>
+</response>
+\end{verbatim}\end{gsc}\end{quote}
+
+The list of document identifiers includes some information about document type and node type. Currently, document types include \gst{simple}, \gst{paged} and \gst{hierarchy}. \gst{simple} is for single section documents, i.e. ones with no sub-structure. \gst{paged} is documents that have a single list of sections, while \gst{hierarchy} type documents have a hierarchy of nested sections. For \gst{paged} and \gst{hierarchy} type documents, the node type identifies whether a section is the root of the document, an internal section, or a leaf.
+
+The term list identifies, for each term in the query, what its frequency in the collection is, how many documents contained that term, and a list of its equivalent terms (if stemming or casefolding was used).
+
+\subsubsection{'browse'-type services}
+
+Browse type services are used for classification browsing. The request consists of a list of classifier identifiers, and some structure parameters listing what structure to retrieve.
+
+\begin{quote}\begin{gsc}\begin{verbatim}
+<request lang="en" to="mgppdemo/ClassifierBrowse" type="process">
+  <paramList>
+    <param name="structure" value="ancestors" />
+    <param name="structure" value="children" />
+  </paramList>
+  <classifierNodeList>
+    <classifierNode nodeID="CL1.2" />
+  </classifierNodeList>
+</request>
+
+<response from="mgppdemo/ClassifierBrowse" type="process">
+  <classifierNodeList>
+    <classifierNode nodeID="CL1">
+      <nodeStructure>
+	<classifierNode nodeID="CL1">
+          <classifierNode nodeID="CL1.2">
+	    <classifierNode nodeID="CL1.2.1" />
+	    <classifierNode nodeID="CL1.2.2" />
+	    <classifierNode nodeID="CL1.2.3" />
+	    <classifierNode nodeID="CL1.2.4" />
+	    <classifierNode nodeID="CL1.2.5" />
+          </classifierNode>	
+	</classifierNode>
+      </nodeStructure>
+    </classifierNode>
+  </classifierNodeList>
+</response>
+\end{verbatim}\end{gsc}\end{quote}
+
+Possible values for structure parameters are \gst{ancestors}, \gst{parent}, \gst{siblings}, \gst{children}, \gst{descendents}. The response gives, for each identifier in the request, a \gst{<nodeStructure>} element with all the requested structure put together into a hierarchy. The structure may include classifier and document nodes. 
+
+
+\subsubsection{'retrieve'-type services}
+
+Retrieval services are special in that requests are not explicitly initiated by a user from a form on a web page, but are called from actions in response to other things. This means that their names are hard-coded into the Actions. DocumentContentRetrieve, DocumentStructureRetrieve and DocumentMetadataRetrieve are the standard names for retrieval services for content, structure, and metadata of documents. Requests to each of these include a list of document identifiers. Because these generally refer to parts of documents, the elements are called \gst{<documentNode>}. For the content, that is all that is required. For the metadata retrieval service, the request also needs parameters specifying what metadata is required. For structure retrieval services, requests need parameters specifying what structure or structural info is required.
+
+Some example requests and responses follow.
+
+Give me the Title metadata for these documents:
+\begin{quote}\begin{gsc}\begin{verbatim}
+
+<request lang="en" to="mgppdemo/DocumentMetadataRetrieve" type="process">
+  <paramList>
+    <param name="metadata" value="Title" />
+  </paramList>
+  <documentNodeList>
+    <documentNode nodeID="HASHac0a04dd14571c60d7fbfd.4.2"/>
+    <documentNode nodeID="HASH010f073f22033181e206d3b7.2.12"/>
+    <documentNode nodeID="HASH010f073f22033181e206d3b7.1"/>
+    ...
+  </documentNodeList>
+</request>
+
+<response from="mgppdemo/DocumentMetadataRetrieve" type="process">
+  <documentNodeList>
+    <documentNode nodeID="HASHac0a04dd14571c60d7fbfd.4.2">
+      <metadataList>
+        <metadata name="Title">Putting snails in your second pen</metadata>
+      </metadataList>
+    </documentNode>
+    <documentNode nodeID="HASH010f073f22033181e206d3b7.2.12">
+      <metadataList>
+        <metadata name="Title">Now you must decide</metadata>
+      </metadataList>
+    </documentNode>
+    <documentNode nodeID="HASH010f073f22033181e206d3b7.1">
+      <metadataList>
+        <metadata name="Title">Introduction</metadata>
+      </metadataList>
+    </documentNode>
+  </documentNodeList>
+</response>
+\end{verbatim}\end{gsc}\end{quote}
+
+One or more parameters specifying metadata may be included in a request. Also, a metadata  value of \gst{all} will retrieve all the metadata for each document.
+
+Any browse-type service must also implement a metadata retrieval service to provide metadata for the nodes in the classification hierarchy. The name of it is the browse service name plus \gst{MetadataRetrieve}. For example, the ClassifierBrowse service described in the previous section should also have a ClassifierBrowseMetadataRetrieve service. The request and response format is exactly the same as for the DocumentMetadataRetrieve service, except that \gst{<documentNode>} elements are replaced by \gst{<classifierNode>} elements (and the corresponding list element is also changed).
+
+Give me the text (content) of this document:
+\begin{quote}\begin{gsc}\begin{verbatim}
+<request lang="en" to="mgppdemo/DocumentContentRetrieve" type="process">
+  <paramList />
+  <documentNodeList>
+    <documentNode nodeID="HASHac0a04dd14571c60d7fbfd.4.2" />
+  </documentNodeList>
+</request>
+
+<response from="mgppdemo/DocumentContentRetrieve" type="process">
+  <documentNodeList>
+    <documentNode nodeID="HASHac0a04dd14571c60d7fbfd.4.2">
+      <nodeContent>&lt;Section&gt; 
+       &lt;/B&gt;&lt;P ALIGN=&quot;JUSTIFY&quot;&gt;&lt;/P&gt;
+       &lt;P ALIGN=&quot;JUSTIFY&quot;&gt;190. When the plants in 
+       your second pen have grown big enough to provide food and 
+       shelter, you can put in the snails.&lt;/P&gt;
+      </nodeContent>
+    </documentNode>
+  </documentNodeList>
+</response>
+\end{verbatim}\end{gsc}\end{quote}
+
+The content of a node is returned in a \gst{<nodeContent>} element. In this case it is escaped HTML.
+
+Give me the ancestors and children of the specified node, along with the number of siblings it has:
+\begin{quote}\begin{gsc}\begin{verbatim}
+<request lang="en" to="mgppdemo/DocumentStructureRetrieve" type="process">
+  <paramList>
+    <param name="structure" value="ancestors" />
+    <param name="structure" value="children" />
+    <param name="info" value="numSiblings" />
+  </paramList>
+  <documentNodeList>
+    <documentNode nodeID="HASHac0a04dd14571c60d7fbfd.4.2" />
+  </documentNodeList>
+</request>
+
+<response from="mgppdemo/DocumentStructureRetrieve" type="process">
+  <documentNodeList>
+    <documentNode nodeID="HASHac0a04dd14571c60d7fbfd.4.2">
+      <nodeStructureInfo>
+        <info name="numSiblings" value="2" />
+      </nodeStructureInfo>
+      <nodeStructure>
+        <documentNode nodeID="HASHac0a04dd14571c60d7fbfd" 
+                docType='hierarchy' nodeType="root">
+          <documentNode nodeID="HASHac0a04dd14571c60d7fbfd.4" 
+                  docType='hierarchy' nodeType="interior">
+            <documentNode nodeID="HASHac0a04dd14571c60d7fbfd.4.2" 
+                   docType='hierarchy' nodeType="leaf" />
+          </documentNode>
+        </documentNode>
+      </nodeStructure>
+    </documentNode>
+  </documentNodeList>
+</response>
+\end{verbatim}\end{gsc}\end{quote}
+
+Structure is returned inside a \gst{<nodeStructure>} element, while structural info is returned in a \gst{<nodeStructureInfo>} element. Possible values for structure parameters are as for browse services: \gst{ancestors}, \gst{parent}, \gst{siblings}, \gst{children}, \gst{descendents}, \gst{entire}. Possible values for info parameters are \gst{numSiblings}, \gst{siblingPosition}, \gst{numChildren}. 
+
+\subsubsection{'process'-type services}\label{sec:process}
+Requests to process-type services are not requests for data---they request some action to be carried out, for example, create a new collection, or import a collection. The response is a status or an error message. The import and build commands may take a long time to complete, so a response is sent back after a successful start to the command. The status may be polled by the requester to see how the process is going. 
+
+Process requests generally contain just a parameter list. Like for any service, the parameters used by a process-type service can be obtained by a describe request to that service.
+
+Here are two example requests for process-services that are part of the build service cluster (hence the addresses all begin with 'build/'), followed by an example response:
+
+\begin{quote}\begin{gsc}\begin{verbatim}
+<request lang='en'  type='process' to='build/NewCollection'>
+  <paramList>
+    <param name='creator' value='me@home.com'/>
+    <param name='collName' value='the demo collection'/>
+    <param name='collShortName' value='demo'/>
+  </paramlist>
+</request>
+
+<request lang='en'  type='process' to='build/ImportCollection'>
+  <paramList>
+    <param name='collection' value='demo'/>
+  </paramlist>
+</request>
+
+<response from="build/ImportCollection">
+  <status code="2" pid="2">Starting process...</status>
+</response>
+\end{verbatim}\end{gsc}\end{quote}
+
+The \gst{code} attribute in the response specifies whether the command has been successfully stated, whether its still going, etc (see Table~\ref{tab:status codes} for a list of currently used codes). The pid attribute specifies a process id number that can be used when querying the status of this process. The content of the status element is (currently) just the output from the process so far. Status messages, which were described in Section~\ref{sec:status}, are used to find out how the process is going, and whether it has finished or not.
+
+\subsubsection{'applet'-type services}
+
+Applet-type services are those that process the data for an applet. A request consists only of a list of parameters, and the response contains an \gst{<appletData>} element that contains the XML data to be returned to the applet. The format of this is entirely specific to the applet---there is no set format to the applet data.
+
+Here is an example request and response, used by the Phind applet:
+\begin{quote}\begin{gsc}\begin{verbatim}
+  <request type='query' to='mgppdemo/PhindApplet'>
+    <paramList>
+      <param name='pc' value='1'/>
+      <param name='pptext' value='health'/>
+      <param name='pfe' value='0'/>
+      <param name='ple' value='10'/>
+      <param name='pfd' value='0'/>
+      <param name='pld' value='10'/>
+      <param name='pfl' value='0'/>
+      <param name='pll' value='10'/>
+    </paramList>
+  </request>
+
+  <response type='query' from='mgppdemo/PhindApplet'>
+    <appletData>
+      <phindData df='9' ef='46' id='933' lf='15' tf='296'>
+        <expansionList end='10' length='46' start='0'>
+          <expansion df='4' id='8880' num='0' tf='59'>
+            <suffix> CARE</suffix>
+          </expansion>
+          ...
+        </expansionList>
+        <documentList end='10' length='9' start='0'>
+          <document freq='78' hash='HASH4632a8a51d33c47a75c559' num='0'>
+            <title>The Courier - N??159 - Sept- Oct 1996 Dossier Investing 
+                   in People Country Reports: Mali ; Western Samoa
+            </title>
+          </document>
+          ...
+        </documentList>
+        <thesaurusList end='10' length='15' start='0'>
+          <thesaurus df='7' id='12387' tf='15' type='RT'>
+            <phrase>PUBLIC HEALTH</phrase>
+          </thesaurus>...
+        </thesaurusList>
+      </phindData>
+    </appletData>
+  </response>
+
+\end{verbatim}\end{gsc}\end{quote}
+
+\subsubsection{'enrich'-type services}
+
+Enrich services typically take some text of documents (inside \gst{<nodeContent>} tags) and returns the text marked up in some way. One example of this is the GatePOSTag service: this identifies Dates, Locations, People and Organizations in the text, and annotates the text with the labels. In the following example, the request is for Location and Dates to be identified.
+
+\begin{quote}\begin{gsc}\begin{verbatim}
+<request lang="en" to="GatePOSTag" type="process">
+  <paramList>
+    <param name="annotationType" value="Date,Location" />
+  </paramList>
+  <documentNodeList>
+    <documentNode nodeID="HASHac0a04dd14571c60d7fbfd">
+      <nodeContent>
+        FOOD AND AGRICULTURE ORGANIZATION OF THE UNITED NATIONS
+        Rome 1986
+        P-69
+        ISBN 92-5-102397-2
+        FAO 1986
+      </nodeContent>
+    </documentNode>
+  </documentNodeList>
+</request>
+
+<response from="GatePOSTag" type="process">
+  <documentNodeList>
+    <documentNode nodeID="HASHac0a04dd14571c60d7fbfd">
+      <nodeContent>
+	FOOD AND AGRICULTURE ORGANIZATION OF THE UNITED NATIONS
+	<annotation type="Location">Rome</annotation> 
+        <annotation type="Date">1986</annotation>
+        P-69
+        ISBN 92-5-102397-2
+        FAO <annotation type="Date">1986</annotation>
+      </nodeContent>
+    </documentNode>
+  </documentNodeList>
+</response>
+\end{verbatim}\end{gsc}\end{quote}
+
+\subsection{Page generation}\label{sec:pagegen} 
+
+A 'page' is some XML or HTML (or other?) data returned in response to an 
+external 'page'-type request. These requests originate from outside \gs\ , for example from a servlet, or Java application, and are received by the Receptionist. As described below in Section~\ref{sec:page-requests}, the requests are XML representations of \gs\  URLs. One of the arguments is action (a). This tells the Receptionist which Action module to pass the request to. 
+
+Action modules decode the rest of the arguments to determine what requests need to be made to the system. One or more internal requests may be made to the MessageRouter. A request for format information from the Collection/Service may also be made. The resulting data is gathered together into a single XML response, \gst{<page>}, and returned to the Receptionist. 
+
+The page format is described in Section~\ref{sec:page-format}. The XML may be returned as is, or may be modified by the Receptionist. The various Receptionists are described in Section~\ref{sec:recepts}. The default receptionist used by a servlet transforms the XML into HTML using XSL stylesheets. Section~\ref{sec:collformat} looks at collection specific formatting, in particular for HTML output.
+Sections~\ref{sec:pageaction} to \ref{sec:systemaction} look at the various actions and what kind of data they gather.
+
+\subsubsection{'page'-type requests and their arguments}\label{sec:page-requests}
+
+These are requests for a 'page' of data---for example, the home page for a site; the query page for a collection; the text of a document. They contain, in XML, a list of arguments specifying what type of page is required. If the external context is a servlet, the arguments represent the 'CGI' arguments in a \gs\  URL.  The two main arguments are \gst{a} (action) and \gst{sa} (subaction). All other arguments are encoded as parameters.
+
+Here are some examples of  requests\footnote{In a servlet context, these correspond to the arguments \gst{a=p\&sa=about\&c=demo\&l=fr}, and \gst{a=q\&l=en\&s=TextQuery\&c=demo\&rt=r\&ca=0\&st=1\&m=10\&q=snail}.}:
+
+\begin{quote}\begin{gsc}\begin{verbatim}
+<request type='page' action='p' subaction='about'
+         lang='fr' output='html'>
+  <paramList>
+    <param name='c' value='demo'/>
+  </paramList>
+</request>
+\end{verbatim}\end{gsc}\end{quote}
+
+\begin{quote}\begin{gsc}\begin{verbatim}
+<request type='page' action='q' lang='en' output='html'>
+  <paramList>
+    <param name='s' value='TextQuery'/>
+    <param name='c' value='demo'/>
+    <param name='rt' value='r'/>
+    <!-- the rest are the service specific params -->
+    <param name='ca' value='0'/> <!-- casefold -->
+    <param name='st' value='1'/> <!-- stem -->
+    <param name='m' value='10'/> <!-- maxdocs -->
+    <param name='q' value='snail'/> <!-- query string -->
+  </paramList>
+</request>
+\end{verbatim}\end{gsc}\end{quote}
+
+There are some standard arguments used in Greenstone, and they are described in Table~\ref{tab:args}. These are used by Receptionists and Actions. The GSParams class specifies all the general basic arguments, and whether they should be saved or not (Some arguments need to be saved during a session, and this needs to be implemented outside \gs\  proper --- currently we do this in the servlet, using servlet session handling). The servlet has an init parameter \gst{params\_class} which specifies which params class to use: GSParams can be subclassed if necessary. The Receptionist and Actions must not have conflicting argument names.
+
+Other arguments are used dynamically and come from the Services. Service arguments must always be saved during a session. Services may be created by different people, and may reside on a different site. There is no guarantee that there is no conflict with argument names between services and actions. Therefore service parameters are namespaced when they are put on the page, whereas interface (receptionist and action) parameters have no namespace. The default namespace is s1 (service1) --- any parameters that are for the service will be prefixed by this. For example, the case parameter for a search will be put in the page as s1.case, and the resulting argument in a search URL will be s1.case. When actions are deciding which parameters need to be sent in a request to a service, they can use the namespace information.
+
+If there are  two or more services combined on a page with a single submit button, they will use namespaces s1, s2, s3 etc as needed. The s  (service) parameter will end up with a list of services. For example, \gst{s=TextQuery,MusicQuery,} and the order of these determines the mapping order of the namespaces, i.e. s1 will map to TextQuery, s2 to MusicQuery.
+
+\begin{table}
+{\footnotesize
+\begin{tabular}{lll}
+\hline
+\bf Argument & \bf Meaning &\bf Typical values \\
+\hline
+a & action & a (applet), q (query), b (browse), p (page), pr (process) \\
+& & s (system)\\
+sa & subaction & home, about (page action)\\
+c & collection or  & demo, build \\
+& service cluster \\
+s & service name & TextQuery, ImportCollection \\
+rt & request type & d (display), r (request), s (status) \\
+ro & response only & 0 or 1 - if set to one, the request is carried out \\
+& & but no processing of the results is done \\
+& & currently only used in process actions \\
+o & output type & XML, HTML, WML \\
+l & language & en, fr, zh ...\\
+d & document id & HASHxxx \\
+r & resource id & ???\\
+pid & process handle & an integer identifying a particular process request \\
+\hline
+\end{tabular}}
+\caption{Generic arguments that can appear in a \gs\  URL}
+\label{tab:args}
+\end{table}
+
+\subsubsection{page format}\label{sec:page-format}
+
+The basic  page format  is:
+\begin{quote}\begin{gsc}\begin{verbatim}
+<page lang='en'>
+  <pageRequest/>
+  <pageResponse/>
+</page>
+\end{verbatim}\end{gsc}\end{quote}
+
+* show configuration and describe whats its used for
+
+There are two main elements in the page: pageRequest, pageResponse. The pageRequest is the original request that came into the Receptionist---this is included so that any parameters  can be preset to their previous values, for example, the query options on the query form. The pageResponse contains all the data that has been gathered from the system by the action. The other two elements contain extra information needed by XSLT. Config contains run-time variables such as the location of the gsdl home directory, the current site name, the name of the executable that is running (e.g. library)---these are needed to allow the XSLT to generate correct HTML URLs. Display contains some of the text strings needed in the interface---these are separate from the XSLT to allow for internationalization.
+
+The following subsections outline, for each action, what data is needed and what requests are generated to send to the system. 
+
+
+Once the XML page has been put together, the page to return to the user is created by transforming the XML using XSLT. The output is HTML at this stage, but it will be possible to generate alternative outputs, such as XML, WML etc. A set of XSLT files defines an 'interface'. Different users can change the look of their web pages by creating new XSLT files for a new 'interface'. Just as we have a sites directory where different sites 'live' (ie where their configuration file and collections are located), we have an interfaces directory where the different interfaces 'live' (ie their transforms and images are located there). The default XSLT files are
+located in interfaces/default/transforms. Collections, sites and other interfaces
+can override these files by having their own copy of the appropriate
+files. New interfaces have their own directory inside interfaces/. Sites and collections can have a transform directory containing XSLT files. The order in which the XSLT files are looked for is collection, site, current
+interface, default interface.\footnote{this currently breaks down for remote sites - need to rethink it a bit.}
+[TODO: describe a bit more?? currently only can get this locally]
+
+\subsubsection{Receptionists}\label{sec:recepts}
+
+The receptionist is the controlling module for the page generation part of \gs\ . It has the job of loading up all the actions, and it knows about the message router it and the actions are supposed to talk to. It routes messages received to the appropriate action (page-type messages) or directly to the message router (all other types). Receptionists also do other things, for example, adding to the page received back from the action any information that is common to all pages.
+
+There are different ways of providing an interface to \gs\ , from web based CGI style (using servlets) to Java GUI applications. These different interfaces require slightly different responses from a receptionist, so we provide several standard types of receptionist.
+
+Receptionist: This is the most basic receptionist. The page it returns consists of the original request, and the response from the action it was sent to. Methods preProcessRequest, and postProcessPage are called on the request and page, respectively, but in this basic receptionist, they don't do anything.
+
+TransformingReceptionist: This extends Receptionist, and overwrites postProcessPage to transform the page using XSLT. An XSLT is listed for each action in the receptionists configuration file, and this is used to transform the page. First, some display information, and configuration information is added to the page. Then it is transformed using the specified XSLT for the action, and returned.
+
+WebReceptionist: The WebReceptionist extends TransformingReceptionist. It doesn't do much else except some argument conversion. To keep the URLs short, parameters from the services are given shortnames, and these are used in the web pages. 
+
+DefaultReceptionist: This extends WebReceptionist, and is the default one for \gsiii\  servlets. Due to the page design, some extra information is needed for each page: some metadata about the current collection. The receptionist sends a describe request to the collection to get this, and appends it to the page before transformation using XSLT.
+
+NZDLReceptionist: (do we want to talk about this?) This is an example of a custom receptionist. For a look-alike nzdl.org system, even more information is needed for each page, namely the list of classifiers available from the ClassifierBrowse service. 
+
+By default, the LibraryServlet uses DefaultReceptionist. However, there is a servlet init-param called \gst{receptionist} which can be set to make the servlet use a different one.
+
+\subsubsection{Collection specific formatting}\label{sec:collformat}
+get format info, transform gsf->xsl. transform xml->html
+
+configuration params are passed in to the transformation
+\subsubsection{CGI arguments}
+
+
+\subsubsection{Page action}\label{sec:pageaction}
+
+PageAction is responsible for displaying kinds of information pages, such as the home page of the library, or the home page of a collection, or the help and preferences pages. These pages are not associated with specific services like the other page types. In general, the data comes from describe requests to various modules.
+The different pages are requested using the subaction argument. For the 'home' page, a 'describe' request is sent to the MessageRouter---this returns a list of all the collections, services, serviceClusters and sites known about. For each collection, its metadata is retrieved via a 'describe' request. This metadata is added into the previous result, which is then added into the page.    For the 'about' page, a \gst{describe} request is sent to the module that the about page is about: this may be a collection or a service cluster.  This returns a list of metadata
+and a list of services.
+
+To get an external html page embedded into a greenstone collection, i.e. a two frame page, with the top frame containing the collection header and navigation bar, and the second frame containg the external page, use subaction html.
+A url would look like
+a=p\&amp;sa=html\&amp;c=collname\&amp;url=externalurl
+
+\subsubsection{Query action}\label{sec:queryaction}
+
+The basic URL is \gst{a=q\&s=TextQuery\&c=demo\&rt=d/r}.
+There are three query services which have been implemented: TextQuery, FieldQuery, and AdvancedFieldQuery. These are all handled in the same way by query action.
+For each page, the service description is requested from the  service  of the current collection (via a describe request).  This is currently done every time the query page is
+displayed, but should be cached. The description includes a list of the parameters available for the query, such as case/stem, max num docs to return, etc. If the request type (rt) parameter is set to d for display, the action only needs to display the form, and this is the only request to the service. Otherwise, the submit button has been pressed, and a query request to the TextQuery service is sent. This has  all the parameters from the URL put into the parameter list. A list of document identifiers
+is returned. A followup query is sent to the MetadataRetrieve service of the collection: the content includes the list of
+documents, with a request for some of their metadata. Which metadata to retrieve is determined by looking through the XSLT that will be used to transform the page. The service description and query result are combined into a page of XML, which is returned to the Receptionist.
+
+\subsubsection{Applet action}\label{sec:appletaction}
+
+There are two types of request to the applet action: \gst{a=a \& rt=d\/} and
+\gst{a=a \& rt=r\/}.  The value \gst{rt=d\/} means ``display the applet.'' A
+\gst{describe} request is sent to the service, which returns the \gst{<applet>} HTML element.  The transformation file \gst{applet.xsl} embeds this
+into the page, and the servlet returns the HTML.
+
+The value \gst{rt=r} signals a request from the applet. A process request containing all the parameters is sent to the applet service. The result contains an appletData element, which contains a single  element - this element is returned
+directly to the applet, in XML. No transformation is done. 
+Because the AppletAction doesn't know or care anything about the applet data, it can work with any applet-service pair.
+
+Note that the applet HTML may need to know the name of the \gst{library}
+program.  However, that name is chosen by the person who installed the software
+and will not necessarily be ``library''.  To get around this, the applet can
+put a parameter called ``library'' into the applet data with a null value:
+\begin{quote}\begin{gsc}\begin{verbatim}
+<PARAM NAME='library' VALUE=''/>
+\end{verbatim}\end{gsc}\end{quote}
+When the AppletAction encounters this parameter it inserts the name of the
+current library servlet as its value.
+
+\subsubsection{Document action}\label{sec:documentaction}
+
+DocumentAction is responsible for displaying a document to the user. The display might involve some metadata and/or text for a document or part of a document. For hierarchical documents, a table of contents may be shown, while for paged documents (those with a single linear list of sections), next and previous page buttons may be shown. These different display types require different information about the document. Depending on the arguments, DocumentAction will send requests to several services: DocumentMetadataRetrieve, DocumentStructureRetrieve and DocumentContentRetrieve.
+
+A basic display, for example, Title and text, involves a metadata request to get the Title, and a content request to get the text. Hierarchical table of contents display requires a structure request. If the entire contents is to be displayed, the parameter \gst{structure=entire} would be sent in the request. Otherwise, parameters \gst{structure=ancestors}, \gst{structure=children} and possibly \gst{structure=siblings} may be used, depending in the position of the current node in the document. These return a hierarchical structure of nodes, containing ancestor nodes, child nodes and sibling nodes, respectively.
+For paged display, the structure is not actually needed. A structure request is still sent, but this time it requests some information, rather the structure itself. The information requested includes the number of siblings and the current position of the current node, or the number of children (if the current node is the root of the document).
+
+Metadata may be requested for the current node, or for any nodes in the structure, and content also. The metadata and content are added into the appropriate nodes in the structure hierarchy, and this is returned as the page data.
+
+\subsubsection{XML Document action}\label{sec:xmldocumentaction}
+
+XMLDocumentAction is a little different to the standard DocumentAction. It operates in two modes, \gst{text} and \gst{toc}. In \gst{text} mode, it will retrieve the content of the current document node using a DocumentContentRetrieve request. In \gst{toc} mode, it retrieves the entire table of contents for the document using a DocumentStructureRetrieve request. Either mode may also retrieve metadata for the current section or each section in the table of contents.
+
+\subsubsection{GS2Browse action}\label{sec:browseaction}
+
+GS2BrowseAction is for displaying \gsii\  style classifiers. 
+\subsubsection{System action}\label{sec:systemaction}
+
+SystemAction allows for manual reconfiguration of various components at run-time. There is no interactive web-page displaying the options, it merely turns a set of CGI arguments into an XML system request. The response from a system request is a message which is displayed to the user.
+
+\begin{table}
+\caption{Configure CGI arguments}
+\label{tab:system-cgi}
+{\footnotesize
+\begin{tabular}{ll}
+\hline
+\bf arg & \bf description\\
+\hline
+a=s & system action\\
+sa=c$|$a$|$d & type of system request: c (configure), a (add/activate), \\
+& d (delete/deactivate) \\
+c=demo &  the request will go to this collection/servicecluster \\
+& instead of the message router\\
+ss=collectionList & subset for configure: only reconfigure this part.\\
+&  For the MessageRouter,  can be serviceClusterList, serviceList, \\
+& collectionList, siteList.\\
+&  For a collection/cluster, can be metadataList or serviceList.\\
+sn=demo & \\
+st=collection& \\
+\hline
+\end{tabular}}
+\end{table}
+
+
+\subsection{Other code information}
+
+Greenstone has a set of Utility classes, which are briefly described in Table~\ref{tab:utils}.
+
+\begin{table}[h]
+\caption{The utility classes in org.greenstone.gsdl3.util}
+\label{tab:utils}
+{\footnotesize
+\begin{tabular}{lp{3.75in}}
+\hline
+\bf Utility class & \bf Description\\
+\hline
+CollectionClassLoader & ClassLoader that knows about a collection's resource directory \\
+DBInfo & Class to hold info from GDBM database entry \\
+Dictionary & wrapper around a Resource Bundle, providing strings with parameters\\
+GDBMWrapper & Wrapper for GDBM database. Uses JavaGDBM\\
+GSConstants & holds some constants used for servlet arguments and configuration variables\\
+GSEntityResolver & an EntityResolver which can be used to find resources such as DTDs\\
+GSFile & class to create all \gs\  file paths e.g. used to locate configuration files, XSLT files and collection data. \\
+GSHTML & provides convenience methods for dealing with HTML, e.g. making strings HTML safe\\
+GSParams & contains names and default values for interface parameters\\
+NZDLParams & a subclass of GSParams which holds default service parameters too, necessary for the classic style interface.\\
+GSPath & used to create, examine and modify message address paths\\
+GSStatus & some static codes for status messages\\ 
+GSXML & lots of methods for extracting information out of \gs\  XML, and creating some common types of elements. Also has static Strings for element and attribute names used by \gs\ .\\
+GSXSLT & some manipulation functions for \gs\  XSLT\\
+GlobalProperties & Holds the global properties (from global.properties) \\
+MacroResolver & Used with replace elements in collection configuration files, replaces a macro or string with another string, metadata or text from a dictionary\\
+GS2MacroResolver & MacroResolver for GS2 collections, that uses the GDBM database\\
+Misc & miscellaneous functions\\
+MyNodeList & A simple implementation of an XML NodeList\\
+OID & class to handle \gs\  (2) OIDs\\
+Processing & Runs an external process and prints the output from the process \\
+SQLQuery & contains a connection to a SQL database, along with some methods for accessing the data, such as converting MG numbers to and from Greenstone OIDs.\\
+XMLConverter & provides methods to create new Documents, parse Strings or Files into Documents, and convert Nodes to Strings\\
+XMLTransformer & methods to transform XML using XSLT \\
+XSLTUtil & contains static methods to be called from within XSLT \\
+\hline
+\end{tabular}}
+\end{table}
+
+
+\newpage
+\section{Developing \gsiii\ : Adding new features}\label{sec:new-features}
+
+[TODO: finish this section ]
+
+\subsection{Creating and using new services}\label{sec:new-services}
+
+There are three parts to adding new services to \gsiii: defining the new service, specifying that it should be loaded, and using it. If you are talking to \gs\ using the SOAP interface, then the firsttwo  parts are all that need to be done. If you are using the Greenstone servlet interface, then you may need to do work for the third part, depending on what kind of new service it is.
+If you are adding a service of a type that is already present, for example, a new query service, then the query action can just use your new service as is (assuming it is set up in the same way as the standard query services).
+However, if it is a new type of service that the interface and actions don't know about, you willl need to add a new action or modify an existing one so that your service is actually used.
+
+\subsubsection{Creating the service}
+
+You will need to write a new Java class which inherits from \gst{org.greenstone.gsdl3.service.ServiceRack} (or a subclass of this). The class will need to implement at least the \gst{configure}, \gst{process<ServiceName>} and \gst{getServiceDescription} methods. There is a dummy class called \gst{MyNewServicesTemplate.java} in \gst{greenstone3/resources/java} which describes these methods and what needs to be done.
+
+\gst{ServiceRack.java} handles the main \gst{process} method. If the request type is 'describe', then it will send back a copy of short\_service\_info, which contains a list of services. If there request type is describe, but for a particular service, then it will call \gst{getServiceDescroption} for that service. For a format request, it will send any format element found in format\_info\_map for that service. For a processing request to a service, then the \gst{process<ServiceName>} method will be called.
+
+Once the class is written, it needs to be compiled up and either included in one of the existing jar files, or added in as a jar file to \gst{greenstone3/web/WEB-INF/lib} or a class file to \gst{greenstone3/web/WEB-INF/classes}.
+
+\subsubsection{Loading the service}
+
+To have the library load in your new service, it needs to be specified in a configuration file somewhere. For a collection service, add a new \gst{<serviceRack>} element to the collection's \gst{buildConfig.xml} file. This element should contain any information that the class needs to configure its service(s). For a site-wide service, add the \gst{<serviceRack>} element to the site's \gst{siteConfig.xml} file, either in the \gst{serviceRackList} or as part of a \gst{serviceCluster}.
+
+\subsubsection{Using the service}
+
+If you are using the SOAP web service, then you can send an XML request directly to the service. The 'address' of the request will be the service name if it is a site-wide service, cluster-name/service-name if it is site-wide but belonging to a cluster, or collection-name/service-name if it belongs to a collection. You will need to know the format of the XML request and response that the service expects and returns.
+
+If you want to access your new service through the current servlet interface that uses actions, then whether you need to do more work or not depends on whatkind of service you have implemented. If you have written a new query or browse service, for example, that has teh same request and response format as the existing services, then you don't need to do anything else. Your collection can just use the new query service straight away.
+If the service is of an existing type, but needs soemthing different in the request/response format, then you may need to modify an existing action to supply or use the new information.
+If the service is of a completely new type, then you will probably need a new action to talk to the service and display the results.
+
+
+\subsection{creating new actions/pages}\label{sec:new-pages}
+
+\subsection{new interfaces}\label{sec:new-interfaces}
+
+It is easy to create new interfaces to \gsiii. Here we are talking about interfaces other than those to display in typical browser.
+
+Handheld devices: Use the standard servlet setup, but with a different set of XSLT files to format the pages for small screens, or use WML.
+
+Java GUI Interface: There are couple of alternatives. Depending on what you want to display in the GUI, you could talk to either a Receptionist or a MessageRouter. The library classes can be set up and compiled into the GUI program.
+Talking to a Receptionist will give you access to pages of XML. It is likely that the standard Receptionist class would be used - this doesn't transform the data to HTML. Queries such as ``give me the home page of a collection'' and ``do the following search'' can be issued. All the data needed for the result view is returned. Queries are quite simple, but are limited to what kinds of Actions are available in the library. 
+Talking to a MessageRouter requires a bit more effort on the part of the GUI program, but results in greater flexibility. The kinds of queries that can be issued are individual units of action, such as ``describe yourself'', ``search'', ``retrieve the content for this document''. More than one request may need to be made for a particular feature of the GUI. However you can ask for any combination of data available in the system, you are not relying on Actions. What you will implement though, may be a lot like the Action code in terms of request sequences.
+
+Interfaces in other programming languages: Because the communication is all XML based, other interfaces can talk to the Java library if a communication protocol is set up. This could be done using SOAP for example. Like for Java GUI interfaces, the program could talk to a Receptionist or to a MessageRouter. 
+e.g. Java interface. where you can interface to. MR vs Receptionist. different receptionists. e.g., handheld - using servlet, transforming recpt, but new set of XSLT Java program other program - talk to recpt but just get back XML data for pages. Java gui - just talk to MR, do all processing itself.
+
+Remote interfaces: remote interfaces can be set up in the same way as above, using a communication protocol between the interface, and the library program.
+
+
+\subsection{New types of collections}\label{sec:new-coll-types}
+
+The standard type of collection is built with the \gsii\ Perl collection building system. There are many options to this, but it is conceivable that these options don't meet the needs of all collection builders. \gsiii\  has an ability to use any type of collection you can come up with, assuming some Java code is provided. 
+
+There are four levels of customization that may be needed with new collections: service, collection, interface XSLT, and action levels. We will use the example collections that come with \gs\  to describe these different levels.
+
+Firstly, new service classes need to be written to provide the functionality to search/browse/whatever the collection. If the services have similar interfaces and functionality to the standard services, this may be all that is needed. For example, MGPP collections were the first to be served in \gsiii\ . When we came to do MG collections, all we had to do was write some new service classes that interacted with MG instead of MGPP. Because these collections used the same type of services, this was all we had to do. The format of the configuration files was similar, they just specified MG serviceRack classes rather than MGPP ones.
+
+The XML Sample Texts (gberg) collection, however, was done quite differently to the standard collections. New services were provided to search the database (built with Lucene) and to provide the documents and parts of documents (using XSLT to transform the raw XML files). The collectionConfig file had some extra information in it: a list of the documents in the collection along with their Titles. Because the standard collection class has no notion of document lists, a new class was created (org.greenstone.gsdl3.collection.XMLCollection). This class is basically the same as a standard collection class except that it looks for and stores in memory the documentList from the collectionConfig file.
+
+To tell \gs\  to load up a different type of collection class, we use another configuration file: \gst{etc/collectionInit.xml}. This specifies the name of the collection class to use.
+Currently, this is all that is specified in that file, but you may want to add parameters for the class etc.
+
+\gst{<collectionInit class="XMLCollection"/>}
+
+The display for the collection is also quite different. The home page for the collection  displays the list of documents. To achieve this, the describe response from the collection had to include the list, and a new XSLT was written for the collection that displayed this. Collection XSLT should be put in the transform directory of the collection\footnote{These are currently only used when running \gs\  in a non-distributed fashion, but it will be added in properly at some stage}.
+
+Document display is  significantly different to standard \gs\ . There are two modes of display: table of contents mode, and content mode. Clicking on a document link from the collection home page takes the user to the table of contents for the collection. Clicking on one of the sections in the table of contents takes them to a display of that section. To facilitate this, not only do we need new XSLT files , we also needed a new action. XMLDocumentAction was created, that used two subactions, toc and text, for the different modes of display.
+
+The Receptionist was told about this new action by the addition of the following element to the interfaceConfig.xml file: 
+
+\begin{gsc}\begin{verbatim}
+<action name='xd' class='XMLDocumentAction'>
+  <subaction name='toc' xslt='document-toc.xsl'/>
+  <subaction name='text' xslt='document-content.xsl'/>
+</action>
+\end{verbatim}\end{gsc}
+
+XSLT files are linked to subactions rather than the action as a whole. The collection supplies the two XSLT files written appropriately for the data it contains.
+
+All links that link to the documents have to be changed to use the xd action rather than the standard d action. These include the links from the home page, and the links from query results.
+
+Querying of the collection is almost the same as usual. The query service provides a list of parameters, does the query and then sends back a list of document identifiers. The standard query action was fine for this collection. The change occurs in the way that the results are displayed---this is accomplished using a format statement supplied in the collectionConfig file inside the search node.
+
+\begin{gsc}\begin{verbatim}
+<search>
+  <format>
+    <gsf:template match="documentNode">
+      <xsl:param name="collName"/>
+      <xsl:param name="serviceName"/>
+      <td>
+        <b><a href="{$library_name}?a=xd&amp;sa=text&amp;c={$collName}&
+            amp;d={@nodeID}&amp;p.a=q&amp;p.s={$serviceName}">
+             <xsl:choose>
+               <xsl:when test="metadataList/metadata[@name='Title']">
+                 <gsf:metadata name="Title"/>
+               </xsl:when>
+               <xsl:otherwise>(section)</xsl:otherwise>
+             </xsl:choose>
+           </a>
+         </b> from <b><a href="{$library_name}?a=xd&amp;sa=toc&amp;
+           c={$collName}&amp;d={@nodeID}.rt&amp;p.a=q&amp;p.s={$serviceName}">
+         <gsf:metadata name="Title" select="root"/></a></b>
+      </td>
+    </gsf:template>
+  </format>
+</search>
+\end{verbatim}\end{gsc}
+
+Instead of displaying an icon and the Title, it displays the Title of the section and the title of the document. Both of these are linked to the document: the section title to the content of that section, the document title to the table of contents for the document. Because these require non-standard arguments to the library, these parts of the template are written in XSLT not \gs\  format language. As is shown here it is perfectly feasible to write a format statement that includes XSLT mixed in with \gs\  format elements.
+
+The document display uses CSS to format the output---these are kept in the collection and specified in the collections XSLT files. The documents also specify DTD files. Due to the way we read in the XML files, Tomcat sometimes has trouble locating the DTDs. One option is to make all the links absolute links to files in the collection folder, the other option is to put them in \gs\ 's DTD folder \gst{\$GSDL3SRCHOME/resources/dtd}. 
+
+\subsection{The Classic Interface}
+
+The library seen at \gst{http://www.greenstone.org/greenstone3/nzdl} is like a mirror to \gst{http://www.nzdl.org}---it aims to present the same collections, in the same way but using \gsiii\  instead of \gsii\ . It uses a new site (nzdl) with a new interface (nzdl) which is based on the classic interface. The web.xml file had a new servlet entry in it to specify the combination of nzdl site and nzdl interface.
+
+The site was created by making a directory called nzdl in the sites folder. A siteConfig file was created. Because it is running on Linux, we were able to link to all the collections in the old \gs\  installation. The convert\_coll\_from\_gs2.pl script was run over all the collections to produce the new XML configuration files.
+
+The classic interface was created to be used by this site (and is now a standard part of Greenstone).
+In many cases, creating a new interface just requires the new images and XSLT  to be added to the new directory(see Sections~\ref{sec:sites-and-ints} and \ref{sec:interface-customise}). This classic interface required a bit more customization.
+
+The standard \gsiii\  navigation bar lists all the services available for the collection. In \gsii\ , the navigation bar provides the search option, and the different classifiers. This is not service specific, but hard coded to the search and classifiers. The XSLT that produces the navigation bar needed to be altered to produce this. But also, a new Receptionist was needed. 
+The standard receptionist (DefaultReceptionist) gathers a little bit of extra information for each page of XML before transforming it: this is the list of services for the collection and their display information, allowing the services to be listed along the navigation bar. This is information that is needed by every page (except for the library home page) and therefore is obtained by the receptionist instead of by each action. The nzdl interface needed a bit more information than this: for the ClassifierBrowse service, if there was one, the list of classifiers and their display elements must be obtained. So a new Receptionist (NZDLReceptionist) was written that inherited from DefaultReceptionist, and added this new info into the page.
+
+One of the servlet initialization parameters is the receptionist class: this was added to the servlet definition in the web.xml file so that the LibraryServlet would load up the right receptionist class.
+
+
+\newpage
+\section{Distributed \gs\ }\label{sec:distributed}
+
+\gs\  is designed to run in a distributed fashion. One \gs\  installation can talk to several sites on different computers. This requires some sort of communication protocol. Any protocol can be used, currently we have a simple SOAP protocol.
+
+more explanation..
+
+\begin{figure}[h]
+  \centering
+  \includegraphics[width=4in]{remote} %5.8
+  \caption{A distributed digital library configuration running over several servers}
+  \label{fig:remote}
+\end{figure}
+
+We have used Apache Axis SOAP implementation. This is run as a servlet in Tomcat. Axis is set up during installation of Greenstone. For more details about SOAP in Greenstone, see Appendix~\ref{app:soap}. Debugging soap is described in Appendix~\ref{app:soap-debug}.
+
+\subsection{Serving a site using soap}
+
+A web service for localsite comes with \gs. However, it is not deployed by default. To deploy it, run run \gst{ant deploy-localsite}. If you want to set up web services for other sites, run \gst{ant soap-deploy-site}. This will prompt you for the sitename (its directory name), and a siteuri - a unique identifier for the web service. Tomcat needs to be running for this to work, and you need to have installed the \gs source code.
+
+The ant target deploys the service for the site specified. A resource file (\gst{<sitename>.wsdd}) is created which is used to specify the service. It can be found in \gst{\$GSDL3HOME/resources/soap}, and is generated from \gst{site.wsdd.template}.
+
+The address of the new SOAP service will be tomcatserver-address/greenstone3/services/sitename, for example, www.greenstone.org/greenstone3/services/localsite.
+
+\subsection{Connecting to a site web service}
+
+There are two ways to use a remote site. First, if you have a local site running, then the site can also connect to other remote sites. In the siteConfig.xml file, you need to add a site element into the siteList element.
+
+For example, to get siteA to talk to siteB, you need to deploy a SOAP server on siteB, then add a \gst{<site>} element to the \gst{<siteList>} of siteA's \gst{siteConfig.xml} file (in \gst{\$GSDL3HOME/sites/siteA/siteConfig.xml}).
+
+In the \gst{<siteList>} element, add the following (substituting the chosen site uri for siteBuri):
+
+\begin{gsc}\begin{verbatim}
+<site name="siteBuri"
+  address="http://localhost:8080/greenstone3/services/siteBuri"
+  type="soap"/>
+\end{verbatim}\end{gsc}
+
+(Note that localhost and 8080 should be changed to the values you entered when installing \gsiii. Localhost will only work for servers on the smae machine.).
+
+If you have changed the siteConfig.xml file for a site that is running, it will need to be reconfigured. Either restart Tomcat, or reconfigure through a URL:
+e.g. \gst{http://localhost:8080/greenstone3/library?a=s\&sa=c}.
+Several sites can be connected to in this manner.
+
+The second option is if you have a receptionist set up on a machine where you have no site, and you only want to connect to a single remote site. Instead of using site\_name in the servlet initialisation parameters (in \$GSDL3HOME/WEB-INF/web.xml), you can specify remote\_site\_name, remote\_site\_type and remote\_site\_address. A communicator object will be set up instead of a MessageRouter and the receptionist will talk to the communicator.
+
+\appendix
+
+\newpage
+\section{Using \gsiii\  from CVS}\label{app:cvs}
+
+\gsiii\  is also available via CVS. You can download the latest version of the code. This is not guaranteed to be stable, in fact it is likely to be unstable. The advantage of using CVS is that you can update the code and get the latest fixes. 
+
+Note that you will need the Java 2 SDK, version 1.4.0 or higher, and Ant (Apache's Java based build tool, http://ant.apache.org) installed.
+
+To check out the \gs\  code, use:
+
+\begin{quote}\begin{gsc}\begin{verbatim}
+cvs -d :pserver:cvs\_anon@cvs.scms.waikato.ac.nz:2402/usr/local/
+           global-cvs/gsdl-src co -P greenstone3
+\end{verbatim}\end{gsc}\end{quote}
+
+If you need it, the password for anonymous CVS access is \gst{anonymous}. Note that some older versions of CVS have trouble accessing this repository due to the port number being present. We are using version 1.11.1p1. 
+
+Greenstone is built and installed using Ant (Apache's Java based build tool, 
+http://ant.apache.org). You will need a Java Development 
+Environment (1.4 or higher), and Ant installed to use Greenstone. You can download Ant from \\\gst{http://ant.apache.org/bindownload.cgi}. Make sure that the environment variables JAVA\_HOME and ANT\_HOME are set.
+
+In the \gst{greenstone3} directory, you can run \gst{'ant'} which will give you a help message.
+Running \gst{'ant -projecthelp'} gives a list of the targets that you can run --- these
+do various things like compile the source code, startup the server etc.
+
+The \gst{README.txt} file has up-to-date instructions for installing from CVS. Briefly, for a first time install, run \gst{'ant prepare install'}.
+
+The file \gst{build.properties} contains various parameters that can be set by the user. Please check these settings before running the installation process. The install process will ask you if you accept the properties before starting.
+For a  non-interactive version of the install, run
+\gst{'ant -Dproperties.accepted=yes install'}
+
+To log the output in build.log, run
+\gst{'ant -Dproperties.accepted=yes -logfile build.log install'}
+
+Compilation includes Java and C/C++. On Windows, you will need to have Visual Studio or equivalent installed. Please check the \gst{compile.windows.c++.setup} property in build.properties --- make sure it is set to the setup script of Visual Studio.
+
+Note: \gst{gs3-setup} sets the environment variables \gst{GSDL3HOME, GSDL3SRCHOME, CLASSPATH, PATH, JAVA\_HOME} and needs to be done in a shell before doing collection building etc. 
+
+To run the library, use the \gst{gs3-server.sh/bat} shell scripts.
+
+\newpage
+\section{Tomcat}\label{app:tomcat}
+
+Tomcat is a servlet container, and \gsiii\  runs as a servlet inside it. 
+
+The file \gst{\$GSDL3SRCHOME/packages/tomcat/conf/server.xml} is the Tomcat configuration file. A context for \gsiii\  is given by the file\\ \gst{\$GSDL3SRCHOME/packages/tomcat/conf/Catalina/localhost/greenstone3.xml}. This tells Tomcat where to find the web.xml file, and what URL (\gst{/greenstone3}) to give it. Anything inside the context directory is accessible via Tomcat\footnote{can we use .htaccess files to restrict access??}. For example, the index.html file that lives in \gst{\$GSDL3HOME} can be accessed through the URL \gst{localhost:8080/greenstone3/index.html}. The gs2mgdemo collection's images can be accessed through \\
+\gst{localhost:8080/greenstone3/sites/localsite/collect/gs2mgdemo/images/}.
+
+
+Greenstone sets up Tomcat to run on port 8080 by default. To change this, you can edit the tomcat.port property in build.properties. If you do this before installing Greenstone, then running 'ant install' will use the new port number. If you want to change it later on, shutdown tomcat, run 'ant configure', then when you restart tomcat it will use the new port.
+
+Note: Tomcat must be shutdown and restarted any time you make changes in the following for those changes to take effect:
+\begin{bulletedlist}
+\begin{gsc}
+\item \$GSDL3HOME/WEB-INF/web.xml
+\item \$GSDL3SRCHOME/packages/tomcat/conf/server.xml
+\end{gsc}
+\item any classes or jar files used by the servlets
+\end{bulletedlist}
+
+On startup, the servlet loads in its collections and services. If the site or collection configuration files are changed, these changes will not take effect until the site/collection is reloaded. This can be done through the reconfiguration messages (see Section~\ref{sec:runtime-config}), or by restarting Tomcat.
+
+We have disabled following symlinks for the greenstone servlet. To enable it, edit \gst{\$GSDL3SRCHOME/packages/tomcat/conf/Catalina/localhost/greenstone3.xml} and set 'allowLinking' to true. 
+
+By default, Tomcat allows directory listings. To disable this, change the 'listings' parameter to false in the default servlet definition, in Tomcat's web.xml file (\gst{\$GSDL3SRCHOME/packages/tomcat/conf/web.xml}):
+
+We have set the greenstone context to be reloadable. This means that if a class or resource file in web/WEB-INF/lib or web/WEB-INF/classes changes, the servlet will be reloaded. This is useful for development, but should be turned off for production mode (set the 'reloadable' attribute to false).
+
+Tomcat uses a Manager to handle HTTP session information. This may be stored between restarts if possible. To use a persistent session handling manager, uncomment the \gst{<Manager>} element in \\
+\gst{\$GSDL3SRCHOME/packages/tomcat/conf/server.xml}. For the default manager, session information is stored in the work directory:\\
+\gst{\$GSDL3SRCHOME/packages/tomcat/work/Catalina/localhost/greenstone3/SESSIONS.ser}. Delete this file to clear the cached session info. Note that Tomcat needs to be shutdown to delete this file.
+
+\subsection{Proxying Tomcat with apache}
+
+Instead of incorporating servlet support into your existing web server, an easy alternative is to proxy Tomcat. The \gst{http://www.greenstone.org/greenstone3} site uses apache to proxy Tomcat. ProxyPass and ProxyPassReverse directives need to be added to the Virtualhost description for the www.greenstone.org server.
+
+\begin{quote}\begin{gsc}
+<VirtualHost xx.xx.xx.xx>\\
+ServerName www.greenstone.org\\
+...\\
+ProxyPass /greenstone3 http://puka.cs.waikato.ac.nz:8080/greenstone3\\
+ProxyPassReverse /greenstone3 http://puka.cs.waikato.ac.nz:8080/greenstone3\\
+</VirtualHost>\\
+\end{gsc}\end{quote}
+
+In our example, the \gsiii\  servlet can be accessed at \\
+\gst{http://www.greenstone.org/greenstone3/library}, instead of at \\
+\gst{http://puka.cs.waikato.ac.nz:8080/greenstone3/library}, which is not publically accessible.
+
+\subsection{Running Tomcat behind a proxy}
+
+Almost everything works fine when Tomcat is running behind a proxy. The only time this causes trouble is if the servlet itself needs to make external HTTP connections. We do this in the infomine demo collection for example. One of the service classes sends HTTP requests to the infomine database at riverside. Since this is going through the proxy, a username and password is needed. It is not sufficient to prompt the user for a password because they are unlikely to have a password for the particular proxy that Tomcat is using. What we have done at present is to put a proxy element in the siteConfig.xml file. Here you have to enter a suitable username and password for the proxy server. Unfortunately these are entered in plain text. And the file is viewable via the servlet. So we need a better solution.
+
+\newpage
+\section{SOAP}\label{app:soap}
+
+Greenstone uses the Apache Axis SOAP implementation for distributed communications. Axis runs as a servlet inside Tomcat, and SOAP web services can be deployed by this Axis servlet. The Greenstone installation process sets up Axis for Tomcat, but does not deploy any services. 
+
+To deploy the SOAP service for localsite, run \gst{ant deploy-localsite}.
+
+To deploy a SOAP service for other sites, run \gst{ant soap-deploy-site}
+
+This will prompt you for the sitename (the site's directory name), and a unique URI for the site. It creates a new SOAPServer class for the site \\(\gst{\$GSDL3SRCHOME/src/java/org/greenstone/gsdl3/SOAPServer<sitename>.java}), creates a resource file for deployment (\gst{\$GSDL3SRCHOME/resources/soap/<sitename>.wsdd}), and then tries to deploy the service.
+
+Information about deployed services is maintained between Tomcat sessions---you only need to deploy something once. To undeploy a site, use \gst{ant undeploy-soap-site}.
+
+The axis services can be accessed at \gst{localhost:8080/greenstone3/index.jsp}.
+
+\subsection{Debugging SOAP}\label{app:soap-debug}
+
+If you need to debug the SOAP stuff for some reason, or just want to look at the SOAP messages that are being passed back and forth, you can use the TCP monitor. This intercepts messages coming in to one port, displays them, and passes them to another port.
+To run it, type:
+
+\begin{quote}\gst{java -cp \$GSDL3HOME/WEB-INF/lib/axis.jar \\
+org.apache.axis.utils.tcpmon}
+\end{quote}
+
+The listen port is the port that you want the monitor to be listening on. It should 'act as' a Listener, with target hostname 127.0.0.1 (localhost), and target port the port that Tomcat is running on (8080). You need to modify the address used to talk to the SOAP service. For example, if you want to monitor traffic between the gateway site and the localsite SOAP server, you will need to edit gateway's siteConfig.xml file and change the port number (in the site element) to whatever you have chosen as the listen port.
+
+For example, in the Admin panel of TCPMonitor the Target Hostname might be 127.0.0.1, and the Target Port \# 8080. Set the Listen Port \# to be a different port, such as 8070 and click Add. This produces a new tab panel where you can see the messages arriving at port 8070 before being forwarded to port 8080. You then need to set your test request from your SOAP application to arrive at port 8070 and you will see copies of the messages in the new tab panel.
+
+
+\newpage
+\section{Tidying up the formatting for imported \gsii\  collections}\label{app:gs2tidy}
+
+\subsection{Format statements: \gsii\  vs \gsiii\ }\label{app:gs2format}
+The following table shows the \gsii\  format elements, and their equivalents in \gsiii\ 
+\begin{table}[h]
+\caption{\gsiii\  equivalents of \gsii\  format statements}
+{\footnotesize
+\begin{tabular}{ll}
+\hline
+\bf \gsii\         & \bf \gsiii\  \\
+\hline
+\gst{[Text]} & \gst{<gsf:text/>} \\
+\gst{[num]} & \gst{<gsf:metadata name='docnum'/>}\\
+\gst{[link][/link]} & \gst{<gsf:link></gsf:link>} or \\
+& \gst{<gsf:link type='document'></gsf:link>}\\
+\gst{[srclink][/srclink]} & \gst{<gsf:link type='source'></gsf:link>}\\
+\gst{[icon]} & \gst{<gsf:icon/>} or \\
+& \gst{<gsf:icon type='document'/>}\\
+\gst{[srcicon]} & \gst{<gsf:icon type='source'/>}\\
+\gst{[Title]} (metadata) & \gst{<gsf:metadata name='Title'/>} or \\
+& \gst{<gsf:metadata name='Title' select='current'/>}\\
+\gst{[parent:Title]} & \gst{<gsf:metadata name='Title' select='parent' />}\\
+\gst{[parent(All):Title]} & \gst{<gsf:metadata name='Title' select='ancestors'/>}\\
+\gst{[parent(Top):Title]} & \gst{<gsf:metadata name='Title' select='root' />}\\
+\gst{[parent(All': '):Title]} & \gst{<gsf:metadata name='Title' select='ancestors'}\\ 
+& \gst{  separator=': ' />}\\
+\gst{[sibling(All': '):Title]} & \gst{<gsf:metadata name='Title' multiple='true'} \\
+& \gst{  separator=': ' />}\\
+\gst{\{Or\}\{[dc.Title],}  & \gst{<gsf:choose-metadata>}\\
+\gst{  [dls.Title], [Title]\}}& \gst{  <gsf:metadata name='dc.Title'/>}\\
+& \gst{  <gsf:metadata name='dls.Title'/>}\\
+& \gst{  <gsf:metadata name='Title'/>}\\
+& \gst{</gsf:choose-metadata>}\\
+\gst{\{If\}\{[parent:Title],} & \gst{<gsf:choose-metadata>}\\
+\gst{  [parent:Title], [Title]\}}& \gst{  <gsf:metadata name='Title' select='parent'/>}\\
+& \gst{  <gsf:metadata name='Title'/>}\\
+& \gst{</gsf:choose-metadata>}\\
+\gst{\{If\}\{[Subject],} & \gst{<gsf:switch>}\\
+\gst{  <td>[Subject]</td>\}}& \gst{  <gsf:metadata name='Subject'/>}\\
+& \gst{  <gsf:when test='exists'>} \\
+& \gst{     <td><gsf:metadata name='Subject'/></td>}\\
+& \gst{  </gsf:when></gsf:switch>}\\
+\hline
+\end{tabular}}
+\end{table}
+\subsection{Cleaning up macros}\label{app:gs2replace}
+
+Here we show some of the replace items that have been used for \gsii\  collections.
+
+Getting rid of silly backslashes:
+\begin{gsc}\begin{verbatim}
+<replace scope='text' macro="\\?\\\(" text="\("/>
+\end{verbatim}\end{gsc}
+
+Macro resolving using resource bundles and metadata:
+\begin{gsc}\begin{verbatim}
+<replace scope='metadata' macro="_magazines_" bundle="NZDLMacros" 
+   key="Magazines"/>
+<replace scope='all' macro='_thisOID_' metadata='archivedir'/>
+<replace macro="_httpcollimg_" 
+   text="sites/localsite/collect/folktale/index/assoc"/>
+\end{verbatim}\end{gsc}
+
+Fixing up broken external links:
+\begin{gsc}\begin{verbatim}
+<replace macro="_httpextlink_&amp;rl=1&amp;href=" 
+   text="?a=d&amp;c=folktale&amp;s0.ext=1&amp;d="/>
+<replace macro="_httpextlink_&amp;rl=0&amp;href=" 
+   text="?a=p&amp;sa=html&amp;c=folktale&amp;url="/>
+\end{verbatim}\end{gsc}
+
+These two examples show how to deal with \gsii's external link macros. The first one is for a 'relative' external link. In this case, the links are like URL's but they actually refer to Greenstone internal documents. So the \gsiii\  link is to the document, but with parameter s0.ext signifying that the d argument will need translating before retrieving the content.
+The second example is a truly external link. This is translated into a HTML type page action, where the URL is presented as a frame along with the collection header in a separate frame.
+
+Sometimes we need to add in macros to be resolved in a second step:
+\begin{gsc}\begin{verbatim}
+<replace macro="_iconpdf_" scope="metadata" 
+   text="&lt;img title='_texticonpdf_' src='interfaces/default/images/ipdf.gif'/&gt;"/>
+<replace macro="_texticonpdf_" scope="metadata" bundle="interface_classic" 
+   key="texticonpdf"/>
+\end{verbatim}\end{gsc}
+
+\end{document}
Index: /greenstone3/trunk/gs3-admin.sh
===================================================================
--- /greenstone3/trunk/gs3-admin.sh	(revision 14125)
+++ /greenstone3/trunk/gs3-admin.sh	(revision 14125)
@@ -0,0 +1,63 @@
+#!/bin/sh
+gailang=en
+
+echo
+    echo "Greenstone Administrator Interface (GAI)"
+    echo "Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato"
+    echo "GAI comes with ABSOLUTELY NO WARRANTY; for details see LICENSE.txt"
+    echo "This is free software, and you are welcome to redistribute it"
+echo
+
+##  -------- Run the Greenstone Administrator Interface --------
+
+# This script must be run from within the directory in which it lives
+thisdir=`pwd`
+if [ ! -f "${thisdir}/gs3-admin.sh" ]; then
+    if [ "$gailang" == "es" ]; then
+        echo "Este guión deberá ejecutarse desde el directorio en el que reside."
+    elif [ "$gailang" == "fr" ]; then
+	echo "Ce script doit être exécuté à partir du répertoire dans lequel il se trouve."
+    elif [ "$gailang" == "ru" ]; then
+	echo "üÔÏÔ ÓËÒÉÐÔ ÄÏÌÖÅÎ ÂÙÔØ ×ÚÑÔ ÉÚ ÄÉÒÅËÔÏÒÉÉ, × ËÏÔÏÒÏÊ ÏÎ ÒÁÓÐÏÌÏÖÅÎ"
+    else
+	echo "This script must be run from the directory in which it resides."
+    fi
+    exit 1
+fi
+
+
+##  ---- Determine GSDL3HOME ----
+gsdl3path=
+
+# Some users may set the above line manually
+if [ "$gsdl3path" == "" ]; then
+    # Check the environment variable first
+    if [ "$GSDL3SRCHOME" != "" ]; then
+	gsdl3path=$GSDL3SRCHOME
+
+    # If it is not set, assume that the GAI is installed as a subdirectory of Greenstone
+    else
+#	pushd .. > /dev/null
+	gsdl3path=`pwd`
+#	popd > /dev/null
+    fi
+fi
+
+# Setup Greenstone3, unless it has already been done
+if [ "$GSDL3HOME" == "" ]; then
+    pushd $gsdl3path > /dev/null
+    source gs3-setup.sh
+    popd > /dev/null
+fi
+
+# Other arguments you can provide to GLI to work around memory limitations, or debug
+# -Xms<number>M    To set minimum memory (by default 32MB)
+# -Xmx<number>M    To set maximum memory (by default the nearest 2^n to the total remaining physical memory)
+# -verbose:gc      To set garbage collection messages
+# -Xincgc          For incremental garbage collection (significantly slows performance)
+# -Xprof           Function call profiling
+# -Xloggc:<file>   Write garbage collection log
+
+# $javapath -classpath classes/:GLI.jar:lib/apache.jar:lib/qfslib.jar:lib/mail.jar:lib/activation.jar org.greenstone.gatherer.GathererProg -gsdl $GSDLHOME -wget $wgetpath $*
+
+java -cp $CLASSPATH org.greenstone.admin.GAI $GSDL3SRCHOME $GSDL3HOME
Index: /greenstone3/trunk/gs3-server.bat
===================================================================
--- /greenstone3/trunk/gs3-server.bat	(revision 14125)
+++ /greenstone3/trunk/gs3-server.bat	(revision 14125)
@@ -0,0 +1,131 @@
+@echo off
+
+set SERVERLANG=en
+
+:: -------- Run the Greenstone 3 Server --------
+
+:: This script must be run from within the directory in which it lives
+if exist gs3-server.bat goto start
+    if "%SERVERLANG%" == "en" echo This script must be run from the directory in which it resides.
+    if "%SERVERLANG%" == "es" echo Este guiÂ¢n deberÂ  ejecutarse desde el directorio en el que reside.
+    if "%SERVERLANG%" == "fr" echo Ce script doit Ëtre exâcutâ âŠ partir du râpertoire dans lequel il se trouve.
+    if "%SERVERLANG%" == "ru" echo ÂÃ¢Â®Ã¢ Ã¡ÂªÃ ÂšÂ¯Ã¢ Â€Â®Â«ÂŠÂ¥Â­ Â¡Ã«Ã¢Ã¬ Â¢Â§Ã¯Ã¢ ÂšÂ§ Â€ÂšÃ Â¥ÂªÃ¢Â®Ã ÂšÂš, Â¢ ÂªÂ®Ã¢Â®Ã Â®Â© Â®Â­ Ã Â Ã¡Â¯Â®Â«Â®ÂŠÂ¥Â­
+    goto exit
+
+:start
+if "%OS%" == "Windows_NT" goto findGSDL
+    :: Invoke a new command processor to ensure there's enough environment space
+    if "%1" == "Second" goto findGSDL
+        command /E:2048 /C %0 Second %1 %2 %3 %4 %5 %6 %7 %8 %9
+        goto done
+
+:findGSDL
+echo.
+if "%SERVERLANG%" == "en" echo Greenstone3 Server
+if "%SERVERLANG%" == "en" echo Copyright (C) 2006, New Zealand Digital Library Project, University Of Waikato
+if "%SERVERLANG%" == "en" echo This program comes with ABSOLUTELY NO WARRANTY; for details see LICENSE.txt
+if "%SERVERLANG%" == "en" echo This is free software, and you are welcome to redistribute it
+
+echo.
+::  ---- Determine GSDL3HOME ----
+set GSDL3PATH=
+
+:: Some users may set the above line manually
+ if not "%GSDL3PATH%" == "" goto prepGSDL
+
+ :: The default location is the current directory
+ set GSDL3PATH=.
+
+ :: If it is set, use the GSDLHOME environment variable
+  if "%GSDL3SRCHOME%" == "" goto prepGSDL
+  set GSDL3PATH=%GSDL3SRCHOME%
+
+:prepGSDL
+:: Setup Greenstone, unless it has already been done
+if not "%GSDL3SRCHOME%" == "" goto doneGSDL
+   call "%GSDL3PATH%\gs3-setup.bat" SetEnv > nul
+
+:doneGSDL
+:: GSDL3PATH is no longer needed, since GSDL3SRCHOME should now be set
+set GSDL3PATH=
+
+:findJava
+:: ---- Check Java exists ----
+set JAVAPATH=
+
+:: Some users may set the above line manually
+if not "%JAVAPATH%" == "" goto testJava
+
+:: If it is set, use the JAVA_HOME environment variable
+ if not "%JAVA_HOME%" == "" goto javahome
+
+:: Check if Java is on the search path
+ echo %PATH%| winutil\which.exe java.exe | winutil\setvar.exe JAVAPATH > setjava.bat
+ call setjava.bat
+ del setjava.bat
+ if not "%JAVAPATH%" == "" goto testJava
+
+    :: Still haven't found anything, so try looking in the registry (gulp!)
+    type nul > jdk.reg
+    regedit /E jdk.reg "HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Development Kit"
+    type jdk.reg > jdk.txt
+    del jdk.reg
+    type nul > jre.reg
+    regedit /E jre.reg "HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment"
+    type jre.reg > jre.txt
+    del jre.reg
+
+    winutil\findjava.exe jdk.txt jre.txt | winutil\setvar.exe JAVAPATH > setjava.bat
+    del jdk.txt
+    del jre.txt
+    call setjava.bat
+    del setjava.bat
+
+   :: If nothing was found in the registry, we're stuck
+   if "%JAVAPATH%" == "" goto noJava
+
+   set JAVAPATH=%JAVAPATH%\bin
+   goto testJava
+
+:javahome
+    set JAVAPATH=%JAVA_HOME%\bin
+
+:testJava
+:: Check that a Java executable has been found
+  if "%SERVERLANG%" == "en" echo Checking Java: %JAVAPATH%
+  if "%SERVERLANG%" == "es" echo Revisando Java: %JAVAPATH%
+  if "%SERVERLANG%" == "fr" echo Vârification de Java: %JAVAPATH%
+  if "%SERVERLANG%" == "ru" echo ÂÃ Â®Â¢Â¥Ã ÂªÂ  Java: %JAVAPATH%
+  if exist "%JAVAPATH%\java.exe" goto checkServer
+
+:noJava
+ echo.
+    if "%SERVERLANG%" == "en" echo Failed to locate an appropriate version of Java. You must install a
+    if "%SERVERLANG%" == "en" echo Java Runtime Environment (version 1.4 or greater) before running the
+    if "%SERVERLANG%" == "en" echo Greenstone3 Server.
+    goto exit
+
+:checkServer
+::---- Check that the server program has been compiled ----
+if exist "server.jar" goto runServer
+if "%SERVERLANG%" == "en" echo "You need to compile the code before running the server"
+goto exit
+
+:runServer
+echo Running the Greenstone Server
+:: -Xms32M          To set minimum memory
+:: -Xmx32M          To set maximum memory
+:: -verbose:gc      To set garbage collection messages
+:: -Xincgc          For incremental garbage collection
+:: -Xprof           Function call profiling
+:: -Xloggc:<file>   Write garbage collection log
+
+"%JAVAPATH%\java" -cp "%CLASSPATH%" org.greenstone.server.Server "%GSDL3SRCHOME%"
+
+:exit
+
+:done
+:: ---- Clean up ----
+set JAVAPATH=
+
+ 
Index: /greenstone3/trunk/gs3-server.sh
===================================================================
--- /greenstone3/trunk/gs3-server.sh	(revision 14125)
+++ /greenstone3/trunk/gs3-server.sh	(revision 14125)
@@ -0,0 +1,107 @@
+#!/bin/sh
+serverlang=en
+
+echo
+echo "Greenstone 3 Server"
+echo "Copyright (C) 2006, New Zealand Digital Library Project, University Of Waikato"
+echo "This software comes with ABSOLUTELY NO WARRANTY; for details see LICENSE.txt"
+echo "This is free software, and you are welcome to redistribute it"
+echo
+
+##  -------- Run the Greenstone 3 Server --------
+
+# This script must be run from within the directory in which it lives
+thisdir=`pwd`
+if [ ! -f "${thisdir}/gs3-server.sh" ]; then
+    if [ "$serverlang" == "es" ]; then
+        echo "Este guión deberá ejecutarse desde el directorio en el que reside."
+    elif [ "$serverlang" == "fr" ]; then
+	echo "Ce script doit être exécuté à partir du répertoire dans lequel il se trouve."
+    elif [ "$serverlang" == "ru" ]; then
+	echo "üÔÏÔ ÓËÒÉÐÔ ÄÏÌÖÅÎ ÂÙÔØ ×ÚÑÔ ÉÚ ÄÉÒÅËÔÏÒÉÉ, × ËÏÔÏÒÏÊ ÏÎ ÒÁÓÐÏÌÏÖÅÎ"
+    else
+	echo "This script must be run from the directory in which it resides."
+    fi
+    exit 1
+fi
+
+
+##  ---- Determine GSDL3SRCHOME ----
+gsdl3path=
+
+# Some users may set the above line manually
+if [ "x$gsdl3path" == "x" ]; then
+    # Check the environment variable first
+    if [ "x$GSDL3SRCHOME" != "x" ]; then
+	gsdl3path=$GSDL3SRCHOME
+    else
+	gsdl3path=`pwd`
+    fi
+fi
+
+# Setup Greenstone3, unless it has already been done
+if [ "x$GSDL3SRCHOME" == "x" ]; then
+    pushd $gsdl3path > /dev/null
+    source gs3-setup.sh
+    popd > /dev/null
+fi
+
+## ---- Check Java exists ----
+javapath=
+
+# Some users may set the above line manually
+if [ "x$javapath" = "x" ]; then
+
+    # If it is set, use the JAVA_HOME environment variable
+    if [ "x$JAVA_HOME" != "x" ]; then
+        javapath="$JAVA_HOME/bin/java"
+
+    # Check if Java is on the search path
+    else
+        javapath=`which java 2> /dev/null`
+    fi
+fi
+
+# Check that a Java executable has been found
+if [ "$glilang" = "es" ]; then
+    echo "Revisando Java: $javapath"
+elif [ "$glilang" = "fr" ]; then
+    echo "V<E9>rification de Java: $javapath"
+elif [ "$glilang" = "ru" ]; then
+    echo "<F0><D2><CF><D7><C5><D2><CB><C1> Java: $javapath"
+else
+    echo "Checking Java: $javapath"
+fi
+if [ ! -x "$javapath" ]; then
+    echo
+    echo "Failed to locate an appropriate version of Java. You must installa"
+    echo "Java Runtime Environment (version 1.4 or greater) before running the"
+    echo "Greenstone Server."
+exit 1
+fi
+
+## -- Check the version of Java is new enough (1.4.0 or higher) to run the Server -- do we need this?
+#`$javapath -classpath . CheckJavaVersion > /dev/null`
+#if [ $? -ne 2 ] ; then
+#   echo "The version of the Java Runtime Environment you have installed is too"
+#   echo "old to run the Greenstone Librarian Interface. Please install a new"
+#   echo "version of the JRE (version 1.4 or newer) and rerun this script."
+#exit 1
+#fi
+
+## ---- Check that the server has been compiled ----
+if [ ! -f server.jar ]; then
+  echo "You need to compile the server before running this script"
+  exit 1
+fi
+
+
+# Other arguments you can provide to java 
+# -Xms<number>M    To set minimum memory (by default 32MB)
+# -Xmx<number>M    To set maximum memory (by default the nearest 2^n to the total remaining physical memory)
+# -verbose:gc      To set garbage collection messages
+# -Xincgc          For incremental garbage collection (significantly slows performance)
+# -Xprof           Function call profiling
+# -Xloggc:<file>   Write garbage collection log
+
+java -cp $CLASSPATH org.greenstone.server.Server $GSDL3SRCHOME 
Index: /greenstone3/trunk/gs3-setup.bat
===================================================================
--- /greenstone3/trunk/gs3-setup.bat	(revision 14125)
+++ /greenstone3/trunk/gs3-setup.bat	(revision 14125)
@@ -0,0 +1,96 @@
+@echo off
+
+if exist gs3-setup.bat goto start
+  echo This script must be run from within the Greenstone 3 home directory
+  goto exit
+
+:start
+:: ---- Set the GSDL3HOME variable to the current directory ----
+cd | winutil\setvar.exe GSDL3SRCHOME > setgsdl3.bat
+call setgsdl3.bat
+del setgsdl3.bat
+echo GSDL3SRCHOME: %GSDL3SRCHOME%
+set GSDL3HOME=%GSDL3SRCHOME%\web
+echo GSDL3HOME: %GSDL3HOME%
+
+:: change if using external tomcat
+set TOMCAT_HOME=%GSDL3SRCHOME%\packages\tomcat
+
+:: ---- Set other important environment variables ----
+set GSDLOS=windows
+set PATH=%PATH%;%GSDL3SRCHOME%\bin;%GSDL3SRCHOME%\bin\script;%GSDL3SRCHOME%\lib\jni;
+
+:: ---- Set the CLASSPATH environment variable ----
+set CLASSPATH=.;%GSDL3HOME%\WEB-INF\classes;%GSDL3SRCHOME%\resources\java;%CLASSPATH%
+if exist setcp.bat del setcp.bat
+for %%j in ("%GSDL3SRCHOME%"\*.jar) do echo set CLASSPATH=%%CLASSPATH%%;%%j>> setcp.bat
+for %%j in ("%GSDL3HOME%"\WEB-INF\lib\*.jar) do echo set CLASSPATH=%%CLASSPATH%%;%%j>> setcp.bat
+for %%j in ("%GSDL3SRCHOME%"\lib\jni\*.jar) do echo set CLASSPATH=%%CLASSPATH%%;%%j>> setcp.bat
+for %%j in ("%TOMCAT_HOME%"\common\endorsed\*.jar) do echo set CLASSPATH=%%CLASSPATH%%;%%j>> setcp.bat
+for %%j in ("%GSDL3SRCHOME%"\build\*.jar) do echo set CLASSPATH=%%CLASSPATH%%;%%j>> setcp.bat
+
+call setcp.bat
+del setcp.bat
+
+echo CLASSPATH: %CLASSPATH%
+
+::cd %GSDL3HOME%
+
+:findJava
+:: ---- Check Java SDK exists ----
+set JAVAPATH=
+
+:: Some users may set the above line manually
+if not "%JAVAPATH%" == "" goto testJava
+   
+:: If it is set, use the JAVA_HOME environment variable
+    if not "%JAVA_HOME%" == "" goto javahome
+
+    :: Check if Java is on the search path
+    echo %PATH%| winutil\which.exe java.exe | winutil\setvar.exe JAVAPATH > setjava.bat
+    call setjava.bat
+    del setjava.bat
+    echo %JAVAPATH%
+    if not "%JAVAPATH%" == "" goto testJava
+
+    :: Still haven't found anything, so try looking in the registry (gulp!)
+    type nul > jdk.reg
+    regedit /E jdk.reg "HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Development Kit"
+    type jdk.reg > jdk.txt
+    del jdk.reg
+    type nul > jre.reg
+    regedit /E jre.reg "HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment"
+    type jre.reg > jre.txt
+    del jre.reg
+
+    winutil\findjava.exe jdk.txt jre.txt | winutil\setvar.exe JAVAPATH > setjava.bat
+    del jdk.txt
+    del jre.txt
+    call setjava.bat
+    del setjava.bat
+
+    :: If nothing was found in the registry, we're stuck
+    if "%JAVAPATH%" == "" goto noJava
+
+    set JAVAPATH=%JAVAPATH%\bin
+    goto testJava
+
+:javahome
+    set JAVAPATH=%JAVA_HOME%\bin
+
+:testJava
+if exist "%JAVAPATH%\java.exe" goto  exit
+
+
+:noJava
+    echo.
+    echo Failed to locate an appropriate version of Java. You must install a
+    echo Java Development Kit (version 1.4 or greater) before running the
+    echo Greenstone 3 Digital Library Software.
+    pause
+    goto exit
+
+:exit
+
+
+
Index: /greenstone3/trunk/gs3-setup.sh
===================================================================
--- /greenstone3/trunk/gs3-setup.sh	(revision 14125)
+++ /greenstone3/trunk/gs3-setup.sh	(revision 14125)
@@ -0,0 +1,132 @@
+# if this file is executed, /bin/sh is used, as we don't start with #!
+# this should work under ash, bash, zsh, ksh, sh style shells.
+
+# make sure we are sourced, and not run
+
+if test "$0" != "`echo $0 | sed s/gs3-setup\.sh//`" ; then
+# if $0 contains "gs3-setup.sh" we've been run... $0 is shellname if sourced.
+# One exception is zsh has an option to set it temporarily to the script name
+  if test -z "$ZSH_NAME" ; then
+  # we aren't using zsh
+  gsdl_not_sourced=true
+  fi
+fi
+
+if test -n "$gsdl_not_sourced" ; then
+  echo "	Error: Make sure you source this script, not execute it. Eg:"
+  echo "		$ source gs3-setup.sh"
+  echo "	or"
+  echo "		$ . ./gs3-setup.sh"
+  echo "	not"
+  echo "		$ ./gs3-setup.sh"
+  unset gsdl_not_sourced
+  exit 1
+fi
+
+if test ! -f gs3-setup.sh ; then
+  echo "You must source the script from within the Greenstone home directory"
+  exit 1
+fi
+
+GSDL3SRCHOME=`pwd`
+GSDL3HOME=$GSDL3SRCHOME/web
+export GSDL3HOME
+export GSDL3SRCHOME
+GSDLOS=`uname -s | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+# check for running bash under cygwin
+if test "`echo $GSDLOS | sed 's/cygwin//'`" != "$GSDLOS" ; then
+    GSDLOS=windows
+fi
+export GSDLOS
+
+#change this if external tomcat
+TOMCAT_HOME=$GSDL3SRCHOME/packages/tomcat
+
+PATH=$GSDL3SRCHOME/bin/script:$GSDL3SRCHOME/bin:$PATH
+export PATH
+MANPATH=$MANPATH:$GSDL3SRCHOME/doc/man
+export MANPATH
+
+CLASSPATH=$GSDL3HOME/WEB-INF/classes:$GSDL3SRCHOME/resources/java:$CLASSPATH
+for JARFILE in $GSDL3SRCHOME/*.jar; do
+    CLASSPATH=$CLASSPATH:$JARFILE
+done
+for JARFILE in $GSDL3SRCHOME/lib/jni/*.jar; do
+    CLASSPATH=$CLASSPATH:$JARFILE
+done
+for JARFILE in $GSDL3HOME/WEB-INF/lib/*.jar; do
+    CLASSPATH=$CLASSPATH:$JARFILE
+done
+for JARFILE in $TOMCAT_HOME/common/endorsed/*.jar; do
+    CLASSPATH=$CLASSPATH:$JARFILE
+done    
+for JARFILE in $GSDL3SRCHOME/build/*.jar; do
+    CLASSPATH=$CLASSPATH:$JARFILE
+done
+
+export CLASSPATH
+
+LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$GSDL3SRCHOME/lib/jni
+export LD_LIBRARY_PATH
+## for mac
+DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$GSDL3SRCHOME/lib/jni
+export DYLD_LIBRARY_PATH
+
+
+# see if we can find java
+java="java"
+jfound=1
+jok=1
+# if JAVAHOME or JAVA_HOME is set we'll use it to determine where java lives, otherwise
+#  we just hope it's on the search path
+if [ "$JAVA_HOME" != "" ] ; then
+    java="$JAVA_HOME/bin/java"
+elif [ "$JAVAHOME" != "" ] ; then
+    java="$JAVAHOME/bin/java"
+    export JAVA_HOME=$JAVAHOME
+else
+    java=`which java 2> /dev/null`
+    if [ ! -x "$java" ]; then
+	echo "Failed to locate Java. You must install a java runtime environment"
+	echo "(version 1.4 or greater) before installing Greenstone 3."
+	jfound=0
+	jok=0
+    else
+	export JAVA_HOME=`echo $java | sed -n 's/[\\\/]bin[\\\/]java$//p'`
+    fi
+fi
+if [ $jfound -eq 1 ]; then
+    javaversion=`$java -version 2>&1 | sed -n 's/^java version \"\(.*\)\"/\1/p'`
+    jvmajor=`echo $javaversion | sed -n 's/^\([0-9]*\).*$/\1/p'`
+    jvminor=`echo $javaversion | sed -n 's/^[0-9]*\.\([0-9]*\).*$/\1/p'`
+    
+    if [ $jvmajor -lt 1 ] ; then
+	jok=0
+    fi
+    if [ $jvmajor -eq 1 ] && [ $jvminor -lt 4 ] ; then
+	jok=0
+    fi
+fi
+
+if [ $jfound -eq 1 ] && [ $jok -eq 0 ] ; then
+    echo "The version of the java runtime environment you have installed is too"
+    echo "old to run Greenstone 3. Please install a new version of the JRE (version"
+    echo "1.4 or newer) and rerun this installation."
+else
+    echo "Your environment has successfully been set up to run Greenstone3"
+fi
+
+#do we need to check for perl???
+# make sure perl is ok
+#perl=`which perl 2> /dev/null`
+# echo "perl: $perl"
+#if [ ! -x "$perl" ] ; then
+#    echo "Greenstone 3 requires perl in order to operate but this installation"
+#    echo "could not detect perl on your system. Please ensure that perl is installed"
+#    echo "and is on your search path then rerun this installation script."
+#    exit 1
+#fi
+
+
+
+
Index: /greenstone3/trunk/lib/perl/cpan/XML/Writer.pm
===================================================================
--- /greenstone3/trunk/lib/perl/cpan/XML/Writer.pm	(revision 14125)
+++ /greenstone3/trunk/lib/perl/cpan/XML/Writer.pm	(revision 14125)
@@ -0,0 +1,1407 @@
+########################################################################
+# Writer.pm - write an XML document.
+# Copyright (c) 1999 by Megginson Technologies.
+# No warranty.  Commercial and non-commercial use freely permitted.
+#
+# $Id$
+########################################################################
+
+package XML::Writer;
+
+require 5.004;
+
+use strict;
+use vars qw($VERSION);
+use Carp;
+use IO;
+
+$VERSION = "0.4";
+
+
+
+
+########################################################################
+# Constructor.
+########################################################################
+
+#
+# Public constructor.
+#
+# This actually does most of the work of the module: it defines closures
+# for all of the real processing, and selects the appropriate closures
+# to use based on the value of the UNSAFE parameter.  The actual methods
+# are just stubs.
+#
+sub new {
+  my ($class, %params) = (@_);
+
+				# If the user wants namespaces,
+				# intercept the request here; it will
+				# come back to this constructor
+				# from within XML::Writer::Namespaces::new()
+  if ($params{NAMESPACES}) {
+    delete $params{NAMESPACES};
+    return new XML::Writer::Namespaces(%params);
+  }
+
+				# Set up $self and basic parameters
+  my $self;
+  my $output;
+  my $unsafe = $params{UNSAFE};
+  my $newlines = $params{NEWLINES};
+  my $dataMode = $params{DATA_MODE};
+  my $dataIndent = $params{DATA_INDENT};
+
+				# If the NEWLINES parameter is specified,
+				# set the $nl variable appropriately
+  my $nl = '';
+  if ($newlines) {
+    $nl = "\n";
+  }
+
+
+				# Parse variables
+  my @elementStack = ();
+  my $elementLevel = 0;
+  my %seen = ();
+
+  my $hasData = 0;
+  my @hasDataStack = ();
+  my $hasElement = 0;
+  my @hasElementStack = ();
+
+  #
+  # Private method to show attributes.
+  #
+  my $showAttributes = sub {
+    my $atts = $_[0];
+    my $i = 1;
+    while ($atts->[$i]) {
+      my $aname = $atts->[$i++];
+      my $value = _escapeLiteral($atts->[$i++]);
+      $output->print(" $aname=\"$value\"");
+    }
+  };
+
+				# Method implementations: the SAFE_
+				# versions perform error checking
+				# and then call the regular ones.
+  my $end = sub {
+    $output->print("\n");
+  };
+
+  my $SAFE_end = sub {
+    if (!$seen{ELEMENT}) {
+      croak("Document cannot end without a document element");
+    } elsif ($elementLevel > 0) {
+      croak("Document ended with unmatched start tag(s): @elementStack");
+    } else {
+      @elementStack = ();
+      $elementLevel = 0;
+      %seen = ();
+      &{$end};
+    }
+  };
+
+  my $xmlDecl = sub {
+    my ($encoding, $standalone) = (@_);
+    if ($standalone && $standalone ne 'no') {
+      $standalone = 'yes';
+    }
+    $encoding = "UTF-8" unless $encoding;
+    $output->print("<?xml version=\"1.0\"");
+    if ($encoding) {
+      $output->print(" encoding=\"$encoding\"");
+    }
+    if ($standalone) {
+      $output->print(" standalone=\"$standalone\"");
+    }
+    $output->print("?>\n");
+  };
+
+  my $SAFE_xmlDecl = sub {
+    if ($seen{ANYTHING}) {
+      croak("The XML declaration is not the first thing in the document");
+    } else {
+      $seen{ANYTHING} = 1;
+      $seen{XMLDECL} = 1;
+      &{$xmlDecl};
+    }
+  };
+
+  my $pi = sub {
+    my ($target, $data) = (@_);
+    if ($data) {
+      $output->print("<?$target $data?>");
+    } else {
+      $output->print("<?$target?>");
+    }
+    if ($elementLevel == 0) {
+      $output->print("\n");
+    }
+  };
+
+  my $SAFE_pi = sub {
+    my ($name, $data) = (@_);
+    $seen{ANYTHING} = 1;
+    if ($name =~ /xml/i) {
+      carp("Processing instruction target begins with 'xml'");
+    } 
+
+    if ($name =~ /\?\>/ || $data =~ /\?\>/) {
+      croak("Processing instruction may not contain '?>'");
+    } else {
+      &{$pi};
+    }
+  };
+
+  my $comment = sub {
+    my $data = $_[0];
+    $output->print("<!-- $data -->");
+    if ($elementLevel == 0) {
+      $output->print("\n");
+    }
+  };
+
+  my $SAFE_comment = sub {
+    my $data = $_[0];
+    if ($data =~ /--/) {
+      carp("Interoperability problem: \"--\" in comment text");
+    }
+
+    if ($data =~ /-->/) {
+      croak("Comment may not contain '-->'");
+    } else {
+      $seen{ANYTHING} = 1;
+      &{$comment};
+    }
+  };
+
+  my $doctype = sub {
+    my ($name, $publicId, $systemId) = (@_);
+    $output->print("<!DOCTYPE $name");
+    if ($publicId) {
+      $output->print(" PUBLIC \"$publicId\" \"$systemId\"");
+    } elsif ($systemId) {
+      $output->print(" SYSTEM \"$systemId\"");
+    }
+    $output->print(">\n");
+  };
+
+  my $SAFE_doctype = sub {
+    my $name = $_[0];
+    if ($seen{DOCTYPE}) {
+      croak("Attempt to insert second DOCTYPE declaration");
+    } elsif ($seen{ELEMENT}) {
+      croak("The DOCTYPE declaration must come before the first start tag");
+    } else {
+      $seen{ANYTHING} = 1;
+      $seen{DOCTYPE} = $name;
+      &{$doctype};
+    }
+  };
+
+  my $startTag = sub {
+    my $name = $_[0];
+    if ($dataMode) {
+      $output->print("\n");
+      $output->print(" " x ($elementLevel * $dataIndent));
+    }
+    $elementLevel++;
+    push @elementStack, $name;
+    $output->print("<$name");
+    &{$showAttributes}(\@_);
+    $output->print("$nl>");
+    if ($dataMode) {
+      $hasElement = 1;
+      push @hasDataStack, $hasData;
+      $hasData = 0;
+      push @hasElementStack, $hasElement;
+      $hasElement = 0;
+    }
+  };
+
+  my $SAFE_startTag = sub {
+    my $name = $_[0];
+
+    _checkAttributes(\@_);
+
+    if ($seen{ELEMENT} && $elementLevel == 0) {
+      croak("Attempt to insert start tag after close of document element");
+    } elsif ($elementLevel == 0 && $seen{DOCTYPE} && $name ne $seen{DOCTYPE}) {
+      croak("Document element is \"$name\", but DOCTYPE is \""
+	    . $seen{DOCTYPE}
+	    . "\"");
+    } elsif ($dataMode && $hasData) {
+      croak("Mixed content not allowed in data mode: element $name");
+    } else {
+      $seen{ANYTHING} = 1;
+      $seen{ELEMENT} = 1;
+      &{$startTag};
+    }
+  };
+
+  my $emptyTag = sub {
+    my $name = $_[0];
+    if ($dataMode) {
+      $output->print("\n");
+      $output->print(" " x ($elementLevel * $dataIndent));
+    }
+    $output->print("<$name");
+    &{$showAttributes}(\@_);
+    $output->print("$nl />");
+    if ($dataMode) {
+      $hasElement = 1;
+    }
+  };
+
+  my $SAFE_emptyTag = sub {
+    my $name = $_[0];
+
+    _checkAttributes(\@_);
+
+    if ($seen{ELEMENT} && $elementLevel == 0) {
+      croak("Attempt to insert empty tag after close of document element");
+    } elsif ($elementLevel == 0 && $seen{DOCTYPE} && $name ne $seen{DOCTYPE}) {
+      croak("Document element is \"$name\", but DOCTYPE is \""
+	    . $seen{DOCTYPE}
+	    . "\"");
+    } elsif ($dataMode && $hasData) {
+      croak("Mixed content not allowed in data mode: element $name");
+    } else {
+      $seen{ANYTHING} = 1;
+      $seen{ELEMENT} = 1;
+      &{$emptyTag};
+    }
+  };
+
+  my $endTag = sub {
+    my $name = $_[0];
+    my $currentName = pop @elementStack;
+    $name = $currentName unless $name;
+    $elementLevel--;
+    if ($dataMode && $hasElement) {
+      $output->print("\n");
+      $output->print(" " x ($elementLevel * $dataIndent));
+    }
+    $output->print("</$name$nl>");
+    if ($dataMode) {
+      $hasData = pop @hasDataStack;
+      $hasElement = pop @hasElementStack;
+    }
+  };
+
+  my $SAFE_endTag = sub {
+    my $name = $_[0];
+    my $oldName = $elementStack[$#elementStack];
+    if ($elementLevel <= 0) {
+      croak("End tag \"$name\" does not close any open element");
+    } elsif ($name && ($name ne $oldName)) {
+      croak("Attempt to end element \"$oldName\" with \"$name\" tag");
+    } else {
+      &{$endTag};
+    }
+  };
+
+  my $characters = sub {
+    my $data = $_[0];
+    if ($data =~ /[\&\<\>]/) {
+      $data =~ s/\&/\&amp\;/g;
+      $data =~ s/\</\&lt\;/g;
+      $data =~ s/\>/\&gt\;/g;
+    }
+    $output->print($data);
+    $hasData = 1;
+  };
+
+  my $SAFE_characters = sub {
+    if ($elementLevel < 1) {
+      croak("Attempt to insert characters outside of document element");
+    } elsif ($dataMode && $hasElement) {
+      croak("Mixed content not allowed in data mode: characters");
+    } else {
+      &{$characters};
+    }
+  };
+
+   my $charactersXML = sub {
+    my $data = $_[0];
+  #  if ($data =~ /[\&\<\>]/) {
+  #    $data =~ s/\&/\&amp\;/g;
+  #    $data =~ s/\</\&lt\;/g;
+  #    $data =~ s/\>/\&gt\;/g;
+  #  }
+    $output->print($data);
+    $hasData = 1;
+  };
+
+  my $SAFE_charactersXML = sub {
+    if ($elementLevel < 1) {
+      croak("Attempt to insert characters outside of document element");
+    } elsif ($dataMode && $hasElement) {
+      croak("Mixed content not allowed in data mode: characters");
+    } else {
+      &{$charactersXML};
+    }
+  };
+
+  
+				# Assign the correct closures based on
+				# the UNSAFE parameter
+  if ($unsafe) {
+    $self = {'END' => $end,
+	     'XMLDECL' => $xmlDecl,
+	     'PI' => $pi,
+	     'COMMENT' => $comment,
+	     'DOCTYPE' => $doctype,
+	     'STARTTAG' => $startTag,
+	     'EMPTYTAG' => $emptyTag,
+	     'ENDTAG' => $endTag,
+	     'CHARACTERS' => $characters,
+	     'CHARACTERSXML' => $charactersXML};
+  } else {
+    $self = {'END' => $SAFE_end,
+	     'XMLDECL' => $SAFE_xmlDecl,
+	     'PI' => $SAFE_pi,
+	     'COMMENT' => $SAFE_comment,
+	     'DOCTYPE' => $SAFE_doctype,
+	     'STARTTAG' => $SAFE_startTag,
+	     'EMPTYTAG' => $SAFE_emptyTag,
+	     'ENDTAG' => $SAFE_endTag,
+	     'CHARACTERS' => $SAFE_characters,
+	     'CHARACTERSXML' => $SAFE_charactersXML};
+  }
+
+				# Query methods
+  $self->{'IN_ELEMENT'} = sub {
+    my ($ancestor) = (@_);
+    return $elementStack[$#elementStack] eq $ancestor;
+  };
+
+  $self->{'WITHIN_ELEMENT'} = sub {
+    my ($ancestor) = (@_);
+    my $el;
+    foreach $el (@elementStack) {
+      return 1 if $el eq $ancestor;
+    }
+    return 0;
+  };
+
+  $self->{'CURRENT_ELEMENT'} = sub {
+    return $elementStack[$#elementStack];
+  };
+
+  $self->{'ANCESTOR'} = sub {
+    my ($n) = (@_);
+    return $elementStack[$#elementStack-$n];
+  };
+
+				# Set and get the output destination.
+  $self->{'GETOUTPUT'} = sub {
+    return $output;
+  };
+
+  $self->{'SETOUTPUT'} = sub {
+    my $newOutput = $_[0];
+				# If there is no OUTPUT parameter,
+				# use standard output
+    unless ($newOutput) {
+      $newOutput = new IO::Handle();
+      $newOutput->fdopen(fileno(STDOUT), "w") ||
+	croak("Cannot write to standard output");
+    }
+    $output = $newOutput;
+  };
+
+  $self->{'SETDATAMODE'} = sub {
+    $dataMode = $_[0];
+  };
+
+  $self->{'GETDATAMODE'} = sub {
+    return $dataMode;
+  };
+
+  $self->{'SETDATAINDENT'} = sub {
+    $dataIndent = $_[0];
+  };
+
+  $self->{'GETDATAINDENT'} = sub {
+    return $dataIndent;
+  };
+
+				# Set the output.
+  &{$self->{'SETOUTPUT'}}($params{'OUTPUT'});
+
+				# Return the blessed object.
+  return bless $self, $class;
+}
+
+
+
+
+########################################################################
+# Public methods
+########################################################################
+
+#
+# Finish writing the document.
+#
+sub end {
+  my $self = shift;
+  &{$self->{END}};
+}
+
+#
+# Write an XML declaration.
+#
+sub xmlDecl {
+  my $self = shift;
+  &{$self->{XMLDECL}};
+}
+
+#
+# Write a processing instruction.
+#
+sub pi {
+  my $self = shift;
+  &{$self->{PI}};
+}
+
+#
+# Write a comment.
+#
+sub comment {
+  my $self = shift;
+  &{$self->{COMMENT}};
+}
+
+#
+# Write a DOCTYPE declaration.
+#
+sub doctype {
+  my $self = shift;
+  &{$self->{DOCTYPE}};
+}
+
+#
+# Write a start tag.
+#
+sub startTag {
+  my $self = shift;
+  &{$self->{STARTTAG}};
+}
+
+#
+# Write an empty tag.
+#
+sub emptyTag {
+  my $self = shift;
+  &{$self->{EMPTYTAG}};
+}
+
+#
+# Write an end tag.
+#
+sub endTag {
+  my $self = shift;
+  &{$self->{ENDTAG}};
+}
+
+#
+# Write a simple data element.
+#
+sub dataElement {
+  my ($self, $name, $data, %atts) = (@_);
+  $self->startTag($name, %atts);
+  $self->characters($data);
+  $self->endTag($name);
+}
+
+#
+# Write character data.
+#
+sub characters {
+  my $self = shift;
+  &{$self->{CHARACTERS}};
+}
+
+sub charactersXML {
+  my $self = shift;
+  &{$self->{CHARACTERSXML}};
+}
+    
+#
+# Query the current element.
+#
+sub in_element {
+  my $self = shift;
+  return &{$self->{IN_ELEMENT}};
+}
+
+#
+# Query the ancestors.
+#
+sub within_element {
+  my $self = shift;
+  return &{$self->{WITHIN_ELEMENT}};
+}
+
+#
+# Get the name of the current element.
+#
+sub current_element {
+  my $self = shift;
+  return &{$self->{CURRENT_ELEMENT}};
+}
+
+#
+# Get the name of the numbered ancestor (zero-based).
+#
+sub ancestor {
+  my $self = shift;
+  return &{$self->{ANCESTOR}};
+}
+
+#
+# Get the current output destination.
+#
+sub getOutput {
+  my $self = shift;
+  return &{$self->{GETOUTPUT}};
+}
+
+
+#
+# Set the current output destination.
+#
+sub setOutput {
+  my $self = shift;
+  return &{$self->{SETOUTPUT}};
+}
+
+#
+# Set the current data mode (true or false).
+#
+sub setDataMode {
+  my $self = shift;
+  return &{$self->{SETDATAMODE}};
+}
+
+
+#
+# Get the current data mode (true or false).
+#
+sub getDataMode {
+  my $self = shift;
+  return &{$self->{GETDATAMODE}};
+}
+
+
+#
+# Set the current data indent step.
+#
+sub setDataIndent {
+  my $self = shift;
+  return &{$self->{SETDATAINDENT}};
+}
+
+
+#
+# Get the current data indent step.
+#
+sub getDataIndent {
+  my $self = shift;
+  return &{$self->{GETDATAINDENT}};
+}
+
+
+#
+# Empty stub.
+#
+sub addPrefix {
+}
+
+
+#
+# Empty stub.
+#
+sub removePrefix {
+}
+
+
+
+
+########################################################################
+# Private functions.
+########################################################################
+
+#
+# Private: check for duplicate attributes.
+# Note - this starts at $_[1], because $_[0] is assumed to be an
+# element name.
+#
+sub _checkAttributes {
+  my %anames;
+  my $i = 1;
+  while ($_[$i]) {
+    my $name = $_[$i];
+    $i += 2;
+    if ($anames{$name}) {
+      croak("Two attributes named \"$name\"");
+    } else {
+      $anames{$name} = 1;
+    }
+  }
+}
+
+#
+# Private: escape an attribute value literal.
+#
+sub _escapeLiteral {
+  my $data = $_[0];
+  if ($data =~ /[\&\<\>\"]/) {
+    $data =~ s/\&/\&amp\;/g;
+    $data =~ s/\</\&lt\;/g;
+    $data =~ s/\>/\&gt\;/g;
+    $data =~ s/\"/\&quot\;/g;
+  }
+  return $data;
+}
+
+
+
+
+########################################################################
+# XML::Writer::Namespaces - subclass for Namespace processing.
+########################################################################
+
+package XML::Writer::Namespaces;
+use strict;
+use vars qw(@ISA);
+use Carp;
+
+@ISA = qw(XML::Writer);
+
+#
+# Constructor
+#
+sub new {
+  my ($class, %params) = (@_);
+
+  my $unsafe = $params{UNSAFE};
+
+				# Snarf the prefix map, if any, and
+				# note the default prefix.
+  my %prefixMap = ();
+  if ($params{PREFIX_MAP}) {
+    %prefixMap = (%{$params{PREFIX_MAP}});
+    delete $params{PREFIX_MAP};
+  }
+  my $defaultPrefix = $prefixMap{''};
+  delete $prefixMap{''};
+
+				# Generate the reverse map for URIs
+  my %uriMap = ();
+  my $key;
+  foreach $key (keys(%prefixMap)) {
+    $uriMap{$prefixMap{$key}} = $key;
+  }
+
+				# Create an instance of the parent.
+  my $self = new XML::Writer(%params);
+
+				# Snarf the parent's methods that we're
+				# going to override.
+  my $OLD_startTag = $self->{STARTTAG};
+  my $OLD_emptyTag = $self->{EMPTYTAG};
+  my $OLD_endTag = $self->{ENDTAG};
+
+				# State variables
+  my $prefixCounter = 1;
+  my @nsDecls = ();
+  my $nsDecls = {};
+  my @nsDefaultDecl = ();
+  my $nsDefaultDecl = undef;
+  my @nsCopyFlag = ();
+  my $nsCopyFlag = 0;
+
+  #
+  # Push the current declaration state.
+  #
+  my $pushState = sub {
+    push @nsDecls, $nsDecls;
+    push @nsDefaultDecl, $nsDefaultDecl;
+    push @nsCopyFlag, $nsCopyFlag;
+    $nsCopyFlag = 0;
+  };
+
+
+  #
+  # Pop the current declaration state.
+  #
+  my $popState = sub {
+    $nsDecls = pop @nsDecls;
+    $nsDefaultDecl = pop @nsDefaultDecl;
+    $nsCopyFlag = pop @nsCopyFlag;
+  };
+
+  #
+  # Generate a new prefix.
+  #
+  my $genPrefix = sub {
+    my $prefix;
+    do {
+      $prefix = "__NS$prefixCounter";
+      $prefixCounter++;
+    } while ($uriMap{$prefix});
+    return $prefix;
+  };
+
+  #
+  # Perform namespace processing on a single name.
+  #
+  my $processName = sub {
+    my ($nameref, $atts, $attFlag) = (@_);
+    my ($uri, $local) = @{$$nameref};
+    my $prefix = $prefixMap{$uri};
+
+				# Is this an element name that matches
+				# the default NS?
+    if (!$attFlag && ($uri eq $defaultPrefix)) {
+      unless ($nsDefaultDecl) {
+	push @{$atts}, 'xmlns';
+	push @{$atts}, $uri;
+	$nsDefaultDecl = 1;
+      }
+      $$nameref = $local;
+      
+				# Is there a straight-forward prefix?
+    } elsif ($prefix) {
+      unless ($nsDecls->{$uri}) {
+				# Copy on write (FIXME: duplicated)
+	unless ($nsCopyFlag) {
+	  $nsCopyFlag = 1;
+	  my %decls = (%{$nsDecls});
+	  $nsDecls = \%decls;
+	}
+	$nsDecls->{$uri} = $prefix;
+	push @{$atts}, "xmlns:$prefix";
+	push @{$atts}, $uri;
+      }
+      $$nameref = "$prefix:$local";
+
+    } else {
+      $prefix = &{$genPrefix}();
+      $prefixMap{$uri} = $prefix;
+      $uriMap{$prefix} = $uri;
+      unless ($nsCopyFlag) {
+	$nsCopyFlag = 1;
+	my %decls = (%{$nsDecls});
+	$nsDecls = \%decls;
+      }
+      $nsDecls->{$uri} = $prefix;
+      push @{$atts}, "xmlns:$prefix";
+      push @{$atts}, $uri;
+      $$nameref = "$prefix:$local";
+    }
+  };
+
+
+  #
+  # Perform namespace processing on element and attribute names.
+  #
+  my $nsProcess = sub {
+    if (ref($_[0]->[0]) eq 'ARRAY') {
+      &{$processName}(\$_[0]->[0], $_[0], 0);
+    }
+    my $i = 1;
+    while ($_[0]->[$i]) {
+      if (ref($_[0]->[$i]) eq 'ARRAY') {
+	&{$processName}(\$_[0]->[$i], $_[0], 1);
+      }
+      $i += 2;
+    }
+  };
+
+  #
+  # Start tag, with NS processing
+  #
+  $self->{STARTTAG} = sub {
+    my $name = $_[0];
+    unless ($unsafe) {
+      _checkNSNames(\@_);
+    }
+    &{$pushState}();
+    &{$nsProcess}(\@_);
+    &{$OLD_startTag};
+  };
+
+
+  #
+  # Empty tag, with NS processing
+  #
+  $self->{EMPTYTAG} = sub {
+    unless ($unsafe) {
+      _checkNSNames(\@_);
+    }
+    &{$pushState}();
+    &{$nsProcess}(\@_);
+    &{$OLD_emptyTag};
+    &{$popState}();
+  };
+
+
+  #
+  # End tag, with NS processing
+  #
+  $self->{ENDTAG} = sub {
+    my $name = $_[0];
+    &{$nsProcess}(\@_);
+    &{$OLD_endTag};
+    &{$popState}();
+  };
+
+
+  #
+  # Processing instruction, but only if not UNSAFE.
+  #
+  unless ($unsafe) {
+    my $OLD_pi = $self->{PI};
+    $self->{PI} = sub {
+      my $target = $_[0];
+      if ($target =~ /:/) {
+	croak "PI target '$target' contains a colon.";
+      }
+      &{$OLD_pi};
+    }
+  };
+
+
+  #
+  # Add a prefix to the prefix map.
+  #
+  $self->{ADDPREFIX} = sub {
+    my ($uri, $prefix) = (@_);
+    if ($prefix) {
+      $prefixMap{$uri} = $prefix;
+      $uriMap{$prefix} = $uri;
+    } else {
+      $defaultPrefix = $uri;
+    }
+  };
+
+
+  #
+  # Remove a prefix from the prefix map.
+  #
+  $self->{REMOVEPREFIX} = sub {
+    my ($uri) = (@_);
+    if ($defaultPrefix eq $uri) {
+      $defaultPrefix = undef;
+    }
+    delete $prefixMap{$uri};
+  };
+
+
+  #
+  # Bless and return the object.
+  #
+  return bless $self, $class;
+}
+
+
+#
+# Add a preferred prefix for a namespace URI.
+#
+sub addPrefix {
+  my $self = shift;
+  return &{$self->{ADDPREFIX}};
+}
+
+
+#
+# Remove a preferred prefix for a namespace URI.
+#
+sub removePrefix {
+  my $self = shift;
+  return &{$self->{REMOVEPREFIX}};
+}
+
+
+#
+# Check names.
+#
+sub _checkNSNames {
+  my $names = $_[0];
+  my $i = 1;
+  my $name = $names->[0];
+
+				# Check the element name.
+  if (ref($name) eq 'ARRAY') {
+    if ($name->[1] =~ /:/) {
+      croak("Local part of element name '" .
+	    $name->[1] .
+	    "' contains a colon.");
+    }
+  } elsif ($name =~ /:/) {
+    croak("Element name '$name' contains a colon.");
+  }
+
+				# Check the attribute names.
+  while ($names->[$i]) {
+    my $name = $names->[$i];
+    if (ref($name) eq 'ARRAY') {
+      my $local = $name->[1];
+      if ($local =~ /:/) {
+	croak "Local part of attribute name '$local' contains a colon.";
+      }
+    } else {
+      if ($name =~ /^(xmlns|.*:)/) {
+	if ($name =~ /^xmlns/) {
+	  croak "Attribute name '$name' begins with 'xmlns'";
+	} elsif ($name =~ /:/) {
+	  croak "Attribute name '$name' contains ':'";
+	}
+      }
+    }
+    $i += 2;
+  }
+}
+
+
+1;
+__END__
+
+
+########################################################################
+# POD Documentation
+########################################################################
+
+=head1 NAME
+
+XML::Writer - Perl extension for writing XML documents.
+
+=head1 SYNOPSIS
+
+  use XML::Writer;
+  use IO;
+
+  my $output = new IO::File(">output.xml");
+
+  my $writer = new XML::Writer(OUTPUT => $output);
+  $writer->startTag("greeting", 
+                    "class" => "simple");
+  $writer->characters("Hello, world!");
+  $writer->endTag("greeting");
+  $writer->end();
+  $output->close();
+
+
+=head1 DESCRIPTION
+
+XML::Writer is a helper module for Perl programs that write an XML
+document.  The module handles all escaping for attribute values and
+character data and constructs different types of markup, such as tags,
+comments, and processing instructions.
+
+By default, the module performs several well-formedness checks to
+catch errors during output.  This behaviour can be extremely useful
+during development and debugging, but it can be turned off for
+production-grade code.
+
+The module can operate either in regular mode in or Namespace
+processing mode.  In Namespace mode, the module will generate
+Namespace Declarations itself, and will perform additional checks on
+the output.
+
+Additional support is available for a simplified data mode with no
+mixed content: newlines are automatically inserted around elements and
+elements can optionally be indented based as their nesting level.
+
+
+=head1 METHODS
+
+=head2 Writing XML
+
+=over 4
+
+=item new([$params])
+
+Create a new XML::Writer object:
+
+  my $writer = new XML::Writer(OUTPUT => $output, NEWLINES => 1);
+
+Arguments are an anonymous hash array of parameters:
+
+=over 4
+
+=item OUTPUT
+
+An object blessed into IO::Handle or one of its subclasses (such as
+IO::File); if this parameter is not present, the module will write to
+standard output.
+
+=item NAMESPACES
+
+A true (1) or false (0, undef) value; if this parameter is present and
+its value is true, then the module will accept two-member array
+reference in the place of element and attribute names, as in the
+following example:
+
+  my $rdfns = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+  my $writer = new XML::Writer(NAMESPACES => 1);
+  $writer->startTag([$rdfns, "Description"]);
+
+The first member of the array is a namespace URI, and the second part
+is the local part of a qualified name.  The module will automatically
+generate appropriate namespace declarations and will replace the URI
+part with a prefix.
+
+=item PREFIX_MAP
+
+A hash reference; if this parameter is present and the module is
+performing namespace processing (see the NAMESPACES parameter), then
+the module will use this hash to look up preferred prefixes for
+namespace URIs:
+
+
+  my $rdfns = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+  my $writer = new XML::Writer(NAMESPACES => 1,
+                               PREFIX_MAP => {$rdfns => 'rdf'});
+
+The keys in the hash table are namespace URIs, and the values are the
+associated prefixes.  If there is not a preferred prefix for the
+namespace URI in this hash, then the module will automatically
+generate prefixes of the form "__NS1", "__NS2", etc.
+
+To set the default namespace, use '' for the prefix.
+
+=item NEWLINES
+
+A true or false value; if this parameter is present and its value is
+true, then the module will insert an extra newline before the closing
+delimiter of start, end, and empty tags to guarantee that the document
+does not end up as a single, long line.  If the paramter is not
+present, the module will not insert the newlines.
+
+=item UNSAFE
+
+A true or false value; if this parameter is present and its value is
+true, then the module will skip most well-formedness error checking.
+If the parameter is not present, the module will perform the
+well-formedness error checking by default.  Turn off error checking at
+your own risk!
+
+=item DATA_MODE
+
+A true or false value; if this parameter is present and its value is
+true, then the module will enter a special data mode, inserting
+newlines automatically around elements and (unless UNSAFE is also
+specified) reporting an error if any element has both characters and
+elements as content.
+
+=item DATA_INDENT
+
+A numeric value; if this parameter is present, it represents the
+indent step for elements in data mode (it will be ignored when not in
+data mode).
+
+=back
+
+=item end()
+
+Finish creating an XML document.  This method will check that the
+document has exactly one document element, and that all start tags are
+closed:
+
+  $writer->end();
+
+=item xmlDecl([$encoding, $standalone])
+
+Add an XML declaration to the beginning of an XML document.  The
+version will always be "1.0".  If you provide a non-null encoding or
+standalone argument, its value will appear in the declaration (and
+non-null value for standalone except 'no' will automatically be
+converted to 'yes').
+
+  $writer->xmlDecl("UTF-8");
+
+=item doctype($name, [$publicId, $systemId])
+
+Add a DOCTYPE declaration to an XML document.  The declaration must
+appear before the beginning of the root element.  If you provide a
+publicId, you must provide a systemId as well, but you may provide
+just a system ID.
+
+  $writer->doctype("html");
+
+=item comment($text)
+
+Add a comment to an XML document.  If the comment appears outside the
+document element (either before the first start tag or after the last
+end tag), the module will add a carriage return after it to improve
+readability:
+
+  $writer->comment("This is a comment");
+
+=item pi($target [, $data])
+
+Add a processing instruction to an XML document:
+
+  $writer->pi('xml-stylesheet', 'href="style.css" type="text/css"');
+
+If the processing instruction appears outside the document element
+(either before the first start tag or after the last end tag), the
+module will add a carriage return after it to improve readability.
+
+The $target argument must be a single XML name.  If you provide the
+$data argument, the module will insert its contents following the
+$target argument, separated by a single space.
+
+=item startTag($name [, $aname1 => $value1, ...])
+
+Add a start tag to an XML document.  Any arguments after the element
+name are assumed to be name/value pairs for attributes: the module
+will escape all '&', '<', '>', and '"' characters in the attribute
+values using the predefined XML entities:
+
+  $writer->startTag('doc', 'version' => '1.0',
+                           'status' => 'draft',
+                           'topic' => 'AT&T');
+
+All start tags must eventually have matching end tags.
+
+=item emptyTag($name [, $aname1 => $value1, ...])
+
+Add an empty tag to an XML document.  Any arguments after the element
+name are assumed to be name/value pairs for attributes (see startTag()
+for details):
+
+  $writer->emptyTag('img', 'src' => 'portrait.jpg',
+                           'alt' => 'Portrait of Emma.');
+
+=item endTag([$name])
+
+Add an end tag to an XML document.  The end tag must match the closest
+open start tag, and there must be a matching and properly-nested end
+tag for every start tag:
+
+  $writer->endTag('doc');
+
+If the $name argument is omitted, then the module will automatically
+supply the name of the currently open element:
+
+  $writer->startTag('p');
+  $writer->endTag();
+
+=item dataElement($name, $data [, $aname1 => $value1, ...])
+
+Print an entire element containing only character data.  This is
+equivalent to
+
+  $writer->startTag($name [, $aname1 => $value1, ...]);
+  $writer->characters($data);
+  $writer->endTag($name);
+
+=item characters($data)
+
+Add character data to an XML document.  All '<', '>', and '&'
+characters in the $data argument will automatically be escaped using
+the predefined XML entities:
+
+  $writer->characters("Here is the formula: ");
+  $writer->characters("a < 100 && a > 5");
+
+You may invoke this method only within the document element
+(i.e. after the first start tag and before the last end tag).
+
+In data mode, you must not use this method to add whitespace between
+elements.
+
+=item setOutput($output)
+
+Set the current output destination, as in the OUTPUT parameter for the
+constructor.
+
+=item getOutput()
+
+Return the current output destination, as in the OUTPUT parameter for
+the constructor.
+
+=item setDataMode($mode)
+
+Enable or disable data mode, as in the DATA_MODE parameter for the
+constructor.
+
+=item getDataMode()
+
+Return the current data mode, as in the DATA_MODE parameter for the
+constructor.
+
+=item setDataIndent($step)
+
+Set the indent step for data mode, as in the DATA_INDENT parameter for
+the constructor.
+
+=item getDataIndent()
+
+Return the indent step for data mode, as in the DATA_INDENT parameter
+for the constructor.
+
+
+=back
+
+=head2 Querying XML
+
+=over 4
+
+=item in_element($name)
+
+Return a true value if the most recent open element matches $name:
+
+  if ($writer->in_element('dl')) {
+    $writer->startTag('dt');
+  } else {
+    $writer->startTag('li');
+  }
+
+=item within_element($name)
+
+Return a true value if any open elemnet matches $name:
+
+  if ($writer->within_element('body')) {
+    $writer->startTag('h1');
+  } else {
+    $writer->startTag('title');
+  }
+
+=item current_element()
+
+Return the name of the currently open element:
+
+  my $name = $writer->current_element();
+
+This is the equivalent of
+
+  my $name = $writer->ancestor(0);
+
+=item ancestor($n)
+
+Return the name of the nth ancestor, where $n=0 for the current open
+element.
+
+=back
+
+
+=head2 Additional Namespace Support
+
+WARNING: you must not use these methods while you are writing a
+document, or the results will be unpredictable.
+
+=over 4
+
+=item addPrefix($uri, $prefix)
+
+Add a preferred mapping between a Namespace URI and a prefix.  See
+also the PREFIX_MAP constructor parameter.
+
+To set the default namespace, omit the $prefix parameter or set it to
+''.
+
+=item removePrefix($uri)
+
+Remove a preferred mapping between a Namespace URI and a prefix.
+
+To set the default namespace, omit the $prefix parameter or set it to
+''.
+
+=back
+
+
+=head1 ERROR REPORTING
+
+With the default settings, the XML::Writer module can detect several
+basic XML well-formedness errors:
+
+=over 4
+
+=item *
+
+Lack of a (top-level) document element, or multiple document elements.
+
+=item *
+
+Unclosed start tags.
+
+=item *
+
+Misplaced delimiters in the contents of processing instructions or
+comments.
+
+=item *
+
+Misplaced or duplicate XML declaration(s).
+
+=item *
+
+Misplaced or duplicate DOCTYPE declaration(s).
+
+=item *
+
+Mismatch between the document type name in the DOCTYPE declaration and
+the name of the document element.
+
+=item *
+
+Mismatched start and end tags.
+
+=item *
+
+Attempts to insert character data outside the document element.
+
+=item *
+
+Duplicate attributes with the same name.
+
+=back
+
+During Namespace processing, the module can detect the following
+additional errors:
+
+=over 4
+
+=item *
+
+Attempts to use PI targets or element or attribute names containing a
+colon.
+
+=item *
+
+Attempts to use attributes with names beginning "xmlns".
+
+=back
+
+To ensure full error detection, a program must also invoke the end
+method when it has finished writing a document:
+
+  $writer->startTag('greeting');
+  $writer->characters("Hello, world!");
+  $writer->endTag('greeting');
+  $writer->end();
+
+This error reporting can catch many hidden bugs in Perl programs that
+create XML documents; however, if necessary, it can be turned off by
+providing an UNSAFE parameter:
+
+  my $writer = new XML::Writer(OUTPUT => $output, UNSAFE => 1);
+
+
+=head1 AUTHOR
+
+David Megginson, david@megginson.com
+
+=head1 SEE ALSO
+
+XML::Parser
+
+=cut
Index: /greenstone3/trunk/resources/dtd/bookfrag.dtd
===================================================================
--- /greenstone3/trunk/resources/dtd/bookfrag.dtd	(revision 14125)
+++ /greenstone3/trunk/resources/dtd/bookfrag.dtd	(revision 14125)
@@ -0,0 +1,529 @@
+<!--This is bookfrag DTD-->
+
+<!--entity declarations-->
+<!--#############################################-->
+
+<!ENTITY % stdatts 
+"ref   IDREF  #IMPLIED
+ id    ID     #IMPLIED
+ type  CDATA  #IMPLIED
+ role  CDATA  #IMPLIED
+ class CDATA  #IMPLIED"
+>
+
+<!ENTITY % inline.class "|quote|emph|ital|reference|date|place|name|graphic|txterr|mkuperr|misc ">
+
+<!ENTITY % block.class "|letter|blockquote|footnote|note|list|deflist|table|blockgraphic">
+
+
+<!-- the top level element-->
+<!--##############################################-->
+
+<!ELEMENT book (acknowledge?,meta*,frontmatter?,bookbody,backmatter?,endmeta*)>
+
+<!--begin top level element declarations-->
+<!--##############################################-->
+
+
+<!--the acknowledge element is for a simple statement 
+designed to be placed at the beginning of the visible document.
+Suggested content:
+  Name of Book
+  Author
+  PG and HWG blurb
+  Original Transcriber + date
+  Marker 
+  e.g.
+  "Origin of the Species by Charles Darwin
+  A project of Project Gutenberg and the HTML Writers Guild.
+  Transcribed by  
+  Markup by Frank Boumphrey. Jan 22 2000"
+  -->
+
+<!ELEMENT acknowledge (#PCDATA %inline.class;)*>
+<!ATTLIST acknowledge
+  %stdatts;
+>
+
+<!--the meta tags are here to provide a means for comment 
+at either the very beginning or end of the document-->
+<!ELEMENT meta EMPTY>
+<!ATTLIST meta
+   content  CDATA  #REQUIRED
+   id       ID     #IMPLIED
+>
+
+<!ELEMENT endmeta EMPTY >
+<!ATTLIST endmeta
+   content  CDATA  #REQUIRED
+   id       ID     #IMPLIED
+>
+
+
+
+<!--the bookbody element contains the body of the book it can 
+consist of either part or chapter divisions-->
+
+<!ELEMENT bookbody (part*|chapter*)>
+
+<!--
+the backmatter element contains the backmatter of the book -->
+
+<!ELEMENT backmatter ((appendix|index|glossary|biblio|note)*,colophon?)>
+
+<!--The endmeta tag is groupedwith its twin meta-->
+
+
+<!--end top level element declarations-->
+
+<!--begin frontmatter element declarations-->
+<!--##############################################-->
+
+<!ELEMENT frontmatter (htitlepage|copypage|epigraph|titlepage|
+                toc|acksect|dedication|preface|introduction|miscfm)*>
+
+<!ELEMENT htitlepage (#PCDATA|title|subtitle|author|para|poem|song %inline.class;)*>
+<!ATTLIST htitlepage
+  %stdatts;
+>
+
+<!ELEMENT copypage (#PCDATA|para|poem|song|note %inline.class;)*>
+<!ATTLIST copypage
+  %stdatts;
+>
+
+<!ELEMENT epigraph (#PCDATA|para|poem|song|note|blockquote %inline.class;)*>
+<!ATTLIST epigraph
+  %stdatts;
+>
+
+
+<!ELEMENT titlepage (#PCDATA|partnum|title|subtitle|author|pubinfo|para|poem|song|note|line %inline.class;)*>
+<!ATTLIST titlepage
+  %stdatts;
+>
+
+<!ELEMENT pubinfo (#PCDATA|para|line %inline.class;)*>
+<!ATTLIST pubinfo
+  %stdatts;
+>
+
+
+<!ELEMENT toc (#PCDATA|title|subtitle|subsubtitle|item|list|deflist %inline.class;)*>
+<!--use type or role to describe toctype="other"-->
+<!ATTLIST toc
+  toctype (contents|maps|graphics|tables|other) "contents" 
+  %stdatts;
+>
+
+<!ELEMENT acksect (#PCDATA|para|poem|song|note %inline.class;)*>
+<!ATTLIST acksect
+  %stdatts;
+>
+
+<!ELEMENT dedication (#PCDATA|title|para|poem|song|note %inline.class;)*>
+<!ATTLIST dedication
+  %stdatts;
+>
+
+
+<!ELEMENT preface ((title|chapheader)?,(para|poem|song|sect1|simplesect %block.class;)*,endchap?,preauthor?)>
+<!ATTLIST preface  %stdatts;
+>
+
+<!ELEMENT introduction ((title|chapheader)?,(para|poem|song|sect1|simplesect %block.class;)*,endchap?)>
+<!ATTLIST introduction  %stdatts;
+>
+
+<!ELEMENT miscfm (#PCDATA|para|poem|song|note %inline.class;)*>
+<!ATTLIST miscfm
+  %stdatts;
+>
+
+<!ELEMENT preauthor (#PCDATA|author %inline.class;)*>
+<!ATTLIST preauthor
+  %stdatts;
+>
+
+
+
+<!--end frontmatter element declarations-->
+
+<!--begin bookbody element declarations-->
+<!--##############################################-->
+
+
+<!ELEMENT part (acknowledge?,(titlepage|toc|htitlepage)*,chapter*)>
+<!ATTLIST part
+  %stdatts;
+>
+
+<!ELEMENT chapter ((title|chapheader)?,(para|poem|song|sect1|simplesect|page %block.class;)*,endchap?)>
+<!ATTLIST chapter  %stdatts;
+>
+
+<!--end bookbody element declarations-->
+
+<!--the lowerlevel bookbody elements-->
+<!--##############################################-->
+
+<!--the chapter heading elements-->
+<!--##############################################-->
+
+
+
+
+<!ELEMENT title (#PCDATA %inline.class;)*>
+<!ATTLIST title
+  %stdatts;
+>
+
+<!ELEMENT subtitle (#PCDATA %inline.class;)*>
+<!ATTLIST subtitle
+  %stdatts;
+>
+
+<!ELEMENT subsubtitle (#PCDATA %inline.class;)*>
+<!ATTLIST subsubtitle
+  %stdatts;
+>
+
+
+
+<!--validity constraint. Only one title,chapnum and chapsummary -->
+<!ELEMENT chapheader (title|subtitle|chapnum|chapsummary|blockquote|para|note)*>
+<!ATTLIST chapheader
+  %stdatts;
+>
+
+
+<!ELEMENT chapnum (#PCDATA %inline.class;)*>
+<!ATTLIST chapnum
+  %stdatts;
+>
+
+<!ELEMENT chapsummary (#PCDATA %inline.class;)*>
+<!ATTLIST chapsummary
+  %stdatts;
+>
+
+
+<!--begin backmatter element declarations-->
+<!--##############################################-->
+
+<!--end backmatter element declarations-->
+
+<!ELEMENT index (title|item|list|deflist|note)*>
+<!ATTLIST index
+  indtype (contents|authors|firstlines|tables|other) "contents" 
+  %stdatts;
+>
+
+<!ELEMENT glossary (title|item|list|deflist|note)*>
+<!ATTLIST glossary  
+  %stdatts;
+>
+
+<!ELEMENT biblio (title|item|list|deflist|note)*>
+<!ATTLIST biblio  
+  %stdatts;
+>
+
+
+<!ELEMENT appendix ((title|chapheader)?,(para|poem|song|sect1|simplesect %block.class;)*,endchap?)>
+<!ATTLIST appendix  %stdatts;
+>
+
+<!ELEMENT colophon (#PCDATA|para|poem|song %inline.class;)*>
+<!ATTLIST colophon
+  %stdatts;
+>
+
+<!--the block elements-->
+<!--##############################################-->
+
+
+<!--validity constraint. Only one title per paragraph-->
+<!ELEMENT para (#PCDATA|title %inline.class;)*>
+<!ATTLIST para
+  %stdatts;
+>
+
+<!ELEMENT simplesect (title,(subtitle|para|poem|song %block.class;)*)>
+<!ATTLIST simplesect
+  %stdatts;
+>
+
+<!ELEMENT sect1 (title,(sect2|simplesect|para|poem|song %block.class;)*)>
+<!ATTLIST sect1
+  %stdatts;
+>
+
+<!ELEMENT sect2 (title,(sect3|simplesect|subtitle|para|poem|song  %block.class;)*)>
+<!ATTLIST sect2
+  %stdatts;
+>
+
+<!ELEMENT sect3 (title,(sect4|simplesect|subtitle|para|poem|song  %block.class;)*)>
+<!ATTLIST sect3
+  %stdatts;
+>
+
+<!ELEMENT sect4 (title,(simplesect|subtitle|para|poem|song  %block.class;)*)>
+<!ATTLIST sect4
+  %stdatts;
+>
+
+<!ELEMENT page (#PCDATA %inline.class;)*>
+<!ATTLIST page
+  %stdatts;
+>
+
+<!ELEMENT misc (#PCDATA %inline.class;)*>
+<!ATTLIST misc
+  %stdatts;
+>
+
+
+
+<!ELEMENT blockquote (title?,(para|poem|song)*,attrib?)>
+<!ATTLIST blockquote
+  %stdatts;
+>
+
+<!ELEMENT attrib (#PCDATA %inline.class;)*>
+<!ATTLIST attrib
+  %stdatts;
+>
+
+<!ELEMENT caption (#PCDATA %inline.class;)*>
+<!ATTLIST caption
+  %stdatts;
+>
+<!--##############################################-->
+<!--poetry and songs in the text-->
+<!ELEMENT poem (#PCDATA|title|subtitle|verse|line|note|footnote %inline.class;)*>
+<!ATTLIST poem
+  %stdatts;
+>
+
+<!ELEMENT song (#PCDATA|title|subtitle|verse|line|note|footnote %inline.class;)*>
+<!ATTLIST song
+  %stdatts;
+>
+
+
+<!ELEMENT verse (title|subtitle|line|note)*>
+<!ATTLIST verse
+  %stdatts;
+>
+
+<!ELEMENT line (#PCDATA %inline.class;)*>
+<!ATTLIST line
+  %stdatts;
+>
+
+
+<!--validity constraint: Only one title per poem or per verse-->
+
+<!--end of poetry in the text-->
+
+<!--letter module-->
+
+<!ELEMENT letter (address|to|from|salut|sig|title|subtitle|para|poem|song|line|note)*>
+<!ATTLIST letter
+  %stdatts;
+>
+
+<!ELEMENT address (#PCDATA|para|line %inline.class;)*>
+<!ATTLIST address
+  %stdatts;
+>
+
+<!ELEMENT to (#PCDATA|para|line %inline.class;)*>
+<!ATTLIST to
+  %stdatts;
+>
+
+
+<!ELEMENT from (#PCDATA|para|line %inline.class;)*>
+<!ATTLIST from
+  %stdatts;
+>
+
+
+<!ELEMENT salut (#PCDATA|para|line %inline.class;)*>
+<!ATTLIST salut
+  %stdatts;
+>
+
+
+<!ELEMENT sig (#PCDATA|para|line %inline.class;)*>
+<!ATTLIST sig
+  %stdatts;
+>
+
+
+<!--end letters module-->
+<!--endchap-->
+<!--##############################################-->
+<!--
+  Endchap should only be used when there is a 
+  considerable ammount of material to be organized.
+  For the occasional note footnote and note will suffice
+-->
+
+<!ELEMENT endchap (para %block.class;)*>
+<!ATTLIST endchap  %stdatts;
+>
+
+<!--lists-->
+<!--##############################################-->
+
+
+<!ELEMENT list (title?,(list|item)*)>
+<!ATTLIST list
+  %stdatts;
+>
+
+<!ELEMENT item (#PCDATA|para|poem|song|simplesect %block.class; %inline.class;)*>
+<!ATTLIST item
+  %stdatts;
+>
+
+<!ELEMENT deflist (title?,(item,desc?,def*)*)>
+<!ATTLIST deflist
+  %stdatts;
+>
+
+<!ELEMENT desc (#PCDATA %inline.class;)*>
+<!ATTLIST desc
+  %stdatts;
+>
+
+<!ELEMENT def (#PCDATA %inline.class;)*>
+<!ATTLIST def
+  %stdatts;
+>
+<!--end lists-->
+<!--table element-->
+<!--##############################################-->
+
+
+<!ELEMENT table (title?,row*,caption?)>
+<!ATTLIST table
+  %stdatts;
+>
+
+<!ELEMENT row (cell)*>
+<!ATTLIST row
+  %stdatts;
+>
+
+<!ELEMENT cell (#PCDATA %block.class; %inline.class;)*>
+<!ATTLIST cell
+  %stdatts;
+>
+
+<!--end table-->
+
+<!--graphics-->
+<!--##############################################-->
+
+<!--
+  Note that the required desc attribute is added 
+  text composed by the marker.
+-->
+
+<!ELEMENT graphic EMPTY >
+<!ATTLIST graphic
+  desc CDATA #REQUIRED
+  href CDATA #REQUIRED
+  %stdatts;
+>
+
+<!ELEMENT blockgraphic (title?,graphic,caption?)>
+<!ATTLIST blockgraphic
+  %stdatts;
+>
+
+
+<!--the inline elements-->
+<!--##############################################-->
+
+
+
+<!ELEMENT footnote (#PCDATA %inline.class;)*>
+<!ATTLIST footnote
+  %stdatts;
+>
+
+<!ELEMENT note (#PCDATA %inline.class;)*>
+<!ATTLIST note
+  %stdatts;
+>
+
+
+<!ELEMENT quote (#PCDATA %inline.class;)*>
+<!ATTLIST quote
+  %stdatts;
+>
+
+<!ELEMENT emph (#PCDATA %inline.class;)*>
+<!ATTLIST emph
+  %stdatts;
+>
+
+<!ELEMENT ital (#PCDATA %inline.class;)*>
+<!ATTLIST ital
+  %stdatts;
+>
+
+<!ELEMENT reference (#PCDATA %inline.class;)*>
+<!ATTLIST reference
+  %stdatts;
+>
+
+<!ELEMENT author (#PCDATA %inline.class;)*>
+<!ATTLIST author
+  %stdatts;
+>
+
+<!ELEMENT date (#PCDATA %inline.class;)*>
+<!ATTLIST date
+  %stdatts;
+>
+
+<!ELEMENT place (#PCDATA %inline.class;)*>
+<!ATTLIST place
+  %stdatts;
+>
+
+<!ELEMENT name (#PCDATA %inline.class;)*>
+<!ATTLIST name
+  %stdatts;
+>
+
+
+<!--use to enclose the text you think is in error
+optional explanation if error is not obvious-->
+<!ELEMENT txterr (#PCDATA)*>
+<!ATTLIST txterr
+  explain  CDATA  #IMPLIED
+  %stdatts;
+>
+
+<!--an explanation is required-->
+<!ELEMENT mkuperr EMPTY>
+<!ATTLIST mkuperr
+  explain  CDATA  #REQUIRED
+  %stdatts;
+>
+
+<!--added as titlepage content  Feb/6/00-->
+<!ELEMENT partnum (#PCDATA %inline.class;)*>
+<!ATTLIST partnum
+  %stdatts;
+>
+
+<!--End of bookfrag dtd-->
Index: /greenstone3/trunk/resources/dtd/entities.dtd
===================================================================
--- /greenstone3/trunk/resources/dtd/entities.dtd	(revision 14125)
+++ /greenstone3/trunk/resources/dtd/entities.dtd	(revision 14125)
@@ -0,0 +1,50 @@
+<!ENTITY nbsp "&#160;">
+<!ENTITY copy "&#169;">
+<!ENTITY mdash "&#151;">
+<!ENTITY ouml "&#214;">
+<!ENTITY dollar "&#36;" >
+<!ENTITY Eacute "&#201;" >
+<!ENTITY eacute "&#233;" >
+<!ENTITY uacute "&#250;">
+<!ENTITY aacute "&#225;">
+<!ENTITY oacute "&#243;">
+<!ENTITY Eacute "&#201;">
+<!ENTITY iacute "&#237;">
+<!ENTITY agrave "&#224;">
+<!ENTITY egrave "&#232;">
+<!ENTITY igrave "&#236;">
+<!ENTITY ograve "&#242;">
+<!ENTITY ugrave "&#249;">
+<!ENTITY aelig "&#230;">
+<!ENTITY acirc "&#226;">
+<!ENTITY ecirc "&#234;">
+<!ENTITY icirc "&#238;">
+<!ENTITY ocirc "&#244;">
+<!ENTITY ucirc "&#251;">
+<!ENTITY ntilde "&#241;">
+<!ENTITY ccedil "&#231;">
+<!ENTITY shy "&#173;">
+<!ENTITY pound "&#163;">
+<!ENTITY percnt "&#37;">
+<!ENTITY percent "&#37;">
+<!ENTITY iuml "&#239;">
+<!ENTITY Iuml "&#207;">
+<!ENTITY amacr "&#257;">
+<!ENTITY Amacr "&#256;">
+<!ENTITY emacr "&#275;">
+<!ENTITY Emacr "&#274;">
+<!ENTITY omacr "&#333;">
+<!ENTITY imacr "&#299;">
+<!ENTITY Imacr "&#298;">
+<!ENTITY Omacr "&#332;">
+<!ENTITY umacr "&#363;">
+<!ENTITY Umacr "&#362;">
+<!ENTITY oslash "&#248;">
+<!ENTITY euml "&#235;">
+<!ENTITY Euml "&#203;">
+<!ENTITY uuml "&#252;">
+<!ENTITY frac14 "&#188;">
+<!ENTITY frac34 "&#190;">
+<!ENTITY half "&#189;">
+<!ENTITY frac12 "&#189;">
+
Index: /greenstone3/trunk/resources/dtd/gutbook1.dtd
===================================================================
--- /greenstone3/trunk/resources/dtd/gutbook1.dtd	(revision 14125)
+++ /greenstone3/trunk/resources/dtd/gutbook1.dtd	(revision 14125)
@@ -0,0 +1,40 @@
+<!--
+GUTBOOK DTD V 1.0
+==================
+
+GENERAL NOTES
++++++++++++++
+This is gutbook dtd version 1.0
+file name is gutpoems1.dtd
+This dtd is a first pass at a dtd for marking up 
+books for project gutenberg.
+It was originally developed for marking up the Darwins books.
+
+REVISION HISTORY
+++++++++++++++++
+Original Author
+Frank Boumphrey  1/19/2000
+
+COPYRIGHT NOTICE
+++++++++++++++++
+This DTD is the copyright of the HTML writers guild.
+Permission is given in perpetuity for any one to use 
+this DTD provided that these notes and this  copyright 
+notice is included.
+
+
+-->
+
+<!--Begin gutbook DTD-->
+<!ELEMENT gutbook (gutblurb,markupblurb,book*,endmarkupblurb?,endgutblurb?)>
+
+<!ELEMENT gutblurb (#PCDATA|para|simplesect|title)*>
+<!ELEMENT markupblurb (#PCDATA|para|simplesect|title)*>
+<!ELEMENT endmarkupblurb (#PCDATA|para|simplesect|title)*>
+<!ELEMENT endgutblurb (#PCDATA|para|simplesect|title)*>
+
+<!--Include bookfrag.dtd-->
+
+<!ENTITY % bookfrag SYSTEM "bookfrag.dtd">
+%bookfrag;
+<!--end of file-->
Index: /greenstone3/trunk/resources/java/SOAPServer.java.in
===================================================================
--- /greenstone3/trunk/resources/java/SOAPServer.java.in	(revision 14125)
+++ /greenstone3/trunk/resources/java/SOAPServer.java.in	(revision 14125)
@@ -0,0 +1,87 @@
+/*
+ *    SOAPServer.java.in: a template for a new SOAPServer
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3;
+
+import org.greenstone.gsdl3.core.MessageRouter;
+import org.greenstone.gsdl3.util.GlobalProperties;
+import org.greenstone.gsdl3.util.GSFile;
+import org.greenstone.gsdl3.util.GSXML;
+import org.w3c.dom.Element;
+import java.io.File;
+
+/**
+ * The server side of a SOAP connection
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @see <a href="http://www.w3.org/TR/SOAP/">Simple Object Access Protocol (SOAP) 1.1 </a>
+ */
+
+public class SOAPServer@sitename@
+{
+    
+    /** The message router we're talking to */
+    protected MessageRouter mr=null;
+    /** the name of the site we are serving */
+    protected String site_name = "@sitename@";
+  
+    /** The no-args constructor */
+    public SOAPServer@sitename@() {
+	String gsdl3_home = GlobalProperties.getGSDL3Home();
+	if (gsdl3_home == null || gsdl3_home.equals("")) {
+	    System.err.println("Couldn't access GSDL3Home from GlobalProerties.getGSDL3HOME, can't initialize the SOAP Server.");
+	    return;
+	}
+	String site_home = GSFile.siteHome(gsdl3_home, this.site_name);
+	
+	File site_file = new File(site_home);
+	if (!site_file.isDirectory()) {
+	    System.err.println("The site directory "+site_file.getPath()+" doesn't exist. Can't initialize the SOAP Server.");
+	    return;
+	}   	
+	mr = new MessageRouter();
+	mr.setSiteName(this.site_name);
+	mr.configure();
+    }
+    
+    
+    public Element [] process (Element [] xml_in) {
+	Element [] result = new Element[xml_in.length];
+	for (int i=0; i<xml_in.length; i++) {
+	    Element req = xml_in[i];
+	    // get rid of the obligatory namespace that axis needs
+	    String tag_name = req.getTagName();
+	    String namespace="";
+	    if (tag_name.indexOf(':')!= -1) {
+		namespace = tag_name.substring(0, tag_name.indexOf(':'));
+		tag_name = tag_name.substring(tag_name.indexOf(':')+1);	
+	    }
+	    Element new_req = GSXML.duplicateWithNewName(req.getOwnerDocument(), req, tag_name, true);
+	    Element r = mr.process(new_req);
+	    // add the namespace back on
+	    //Element new_res = r;
+	    //if (!namespace.equals("")) {
+	    //	new_res = GSXML.duplicateWithNewName(r.getOwnerDocument(), r, namespace+r.getTagName(), true);
+	    //}
+	    result[i] = r;
+	}
+	return result;
+    }   
+}
+
Index: /greenstone3/trunk/resources/java/gai.properties
===================================================================
--- /greenstone3/trunk/resources/java/gai.properties	(revision 14125)
+++ /greenstone3/trunk/resources/java/gai.properties	(revision 14125)
@@ -0,0 +1,49 @@
+#***** GAI *****
+# Currently Enabled and Disabled display the same text but in different
+# colours. If necessary this can be changed.
+GAI.Configuration:Configuration
+GAI.Conf_Tooltip: Maintains the configuration setting
+GAI.Ext:Ext
+GAI.Ext_Tooltip:Fedora & DSpace Search
+GAI.Monitor:Monitor
+GAI.Monitor_Tooltip:XXXXXXXXXXXXXXXX
+GAI.Log:Log
+GAI.Log_Tooltip:Examine the relevant log files
+
+Menu.Edit:Edit
+Menu.File:File
+Menu.File_Exit:Exit
+Menu.File_Save:Save
+Menu.Help:Help
+Menu.Help_About:About...
+
+#***** ConfPane *****
+ConfPane.Conf_Content:Configuration file content
+ConfPane.Conf_List:Configuration settings
+ConfPane.Tomcat_Startup:Start Tomcat
+ConfPane.Tomcat_Startup_Tooltip:Click this buttone to startup the Tomcat server
+ConfPane.Tomcat_Shutdown:Stop Tomcat
+ConfPane.Tomcat_Shutdown_Tooltip:Click this buttone to shutdown the Tomcat serve
+r
+ConfPane.Tomcat_Restart:Restart Tomcat
+ConfPane.Tomcat_Restart_Tooltip:Click this button to restart the Tomcat server
+(which will shutdown Tomcat server and restart it again)
+ConfPane.MySQL_Startup:Start MySQL
+ConfPane.MySQL_Startup_Tooltip:Click this button to startup the MYSQL Server
+ConfPane.MySQL_Shutdown:Stop MySQL
+ConfPane.MySQL_Shutdown_Tooltip:Click this button to shutdown the MYSQL Server
+ConfPane.MySQL_Restart:Restart MySQL
+ConfPane.MySQL_Restart_Tooltip:Click this button to restart the MYSQL server(which will shutdown MYSQL server and restart it again
+#***** ExtPane *****
+#***** MonitorPane *****
+#***** LogPane *****
+LogPane.Clear_Log:Clear Log
+LogPane.Clear_Log_Tooltip:Clear the log file
+LogPane.Log_List:Log List
+LogPane.Log_Content:Log Content
+LogPane.Reload_Log:Reload Log
+LogPane.Reload_Log_Tooltip:Reload the contents of this log file
+#**********************
+#***** Sources *****
+Source.General:General
+#*******************
Index: /greenstone3/trunk/resources/java/global.properties.in
===================================================================
--- /greenstone3/trunk/resources/java/global.properties.in	(revision 14125)
+++ /greenstone3/trunk/resources/java/global.properties.in	(revision 14125)
@@ -0,0 +1,19 @@
+## greenstone home
+gsdl3.home=@gsdl3home@
+gsdl3.version=@gsdl3version@
+
+# tomcat info
+tomcat.server=@tomcat.server@
+tomcat.port=@tomcat.port@
+tomcat.context=greenstone3
+
+## Proxy setup - set these if you are behind a firewall and you want services that access the internet
+# The proxy server name 
+proxy.host=
+# The proxy server port
+proxy.port=
+# A user name to use when talking to the proxy server 
+proxy.user=
+# A password to use when talking to the proxy server 
+proxy.password=
+
Index: /greenstone3/trunk/resources/java/log4j.properties.in
===================================================================
--- /greenstone3/trunk/resources/java/log4j.properties.in	(revision 14125)
+++ /greenstone3/trunk/resources/java/log4j.properties.in	(revision 14125)
@@ -0,0 +1,60 @@
+## greenstone home 
+gsdl3.home=@gsdl3home@
+
+##Configure log4j's operation at the meta level                              
+##Observe log4j parsing this file
+#log4j.debug=true
+##Set this to false for log4j to actually obey the log4j.disable property(next)
+log4j.disableOverride=false
+##Disable all logging in all categories for messages with priority equal to
+##or lower than the one given here
+log4j.disable=DEBUG
+
+#####configure the loggers####
+##general logger                                                   
+log4j.rootCategory=INFO, infolog
+
+##usage logger
+log4j.category.org.greenstone.gsdl3.LibraryServlet=INFO, usagelog
+log4j.additivity.org.greenstone.gsdl3.LibraryServlet=false
+
+##server logger
+log4j.category.org.greenstone.server=INFO, serverlog
+log4j.additivity.org.greenstone.server=false
+
+#####configure appenders and their oprions####                                  
+##general logger
+log4j.appender.infolog=org.apache.log4j.RollingFileAppender
+log4j.appender.infolog.File=${gsdl3.home}/logs/greenstone.log
+#Control the maximum log file size
+log4j.appender.infolog.MaxFileSize=100KB
+#Keep backup file(s) (backups will be in filename.1, .2, .3 etc.)
+log4j.appender.infolog.MaxBackupIndex=3
+
+##usage logger
+log4j.appender.usagelog=org.apache.log4j.RollingFileAppender
+log4j.appender.usagelog.File=${gsdl3.home}/logs/usage.log
+#Control the maximum log file size
+log4j.appender.usagelog.MaxFileSize=1000KB
+
+##Server's logger
+log4j.appender.serverlog=org.apache.log4j.RollingFileAppender
+log4j.appender.serverlog.File=${gsdl3.home}/logs/server.log
+
+
+#####Configure appender layouts and their options#### 
+## general logger layout
+log4j.appender.infolog.layout=org.apache.log4j.PatternLayout
+log4j.appender.infolog.layout.ConversionPattern=%-5p: [%d{yyyy-MM-dd hh:mm:ss}] %C{1}.%M()%n %m%n
+
+##usage logger layout
+# Usage log contains:                                                        
+#      loggingTime + servletName + args (in URL plus saved in a session) +  
+#      remoteAddress + sessionID + browerInfo                               
+log4j.appender.usagelog.layout=org.apache.log4j.PatternLayout
+log4j.appender.usagelog.layout.ConversionPattern=[%d{yyyy-MM-dd hh:mm:ss}] %m%n
+
+##server logger layout
+log4j.appender.serverlog.layout=org.apache.log4j.PatternLayout
+log4j.appender.serverlog.layout.ConversionPattern=%-5p: [%d{yyyy-MM-dd hh:mm:ss}] %C{1}.%M()%n %m%n
+
Index: /greenstone3/trunk/resources/java/server.properties
===================================================================
--- /greenstone3/trunk/resources/java/server.properties	(revision 14125)
+++ /greenstone3/trunk/resources/java/server.properties	(revision 14125)
@@ -0,0 +1,32 @@
+ServerSettings.Title=Server settings
+ServerSettings.Tomcat_Port=Tomcat port:
+ServerSettings.Servlet=Servlet:
+ServerSettings.Auto_Start=Enter the library automatically
+ServerSettings.OK=OK
+ServerSettings.Cancel=Cancel
+ServerSettings.DefaultBrowser=Default browser
+ServerSettings.OtherBrowser=Other browser
+ServerSettings.ChooseBrowser=Enter library using:
+ServerSettings.Browse=Browse
+
+ServerControl.EnterLibrary=Enter Library
+ServerControl.RestartLibrary=Restart Library
+ServerControl.StartServer=Start Server
+ServerControl.Version=Version {0}
+ServerControl.Frame_Title=Greenstone Server
+ServerControl.Title=Greenstone3 Digital Library
+ServerControl.Help_RestartLibrary=Press the 'Restart Library' button to restart the server, launch a browser and enter the library
+ServerControl.Help_EnterLibrary=Press the 'Enter Library' button to launch a browser and enter the library
+ServerControl.Starting=Starting server...
+ServerControl.Configuring=Configuring server...
+ServerControl.Stopping=Stopping server...
+ServerControl.LaunchingBrowser=Launching browser...
+ServerControl.LaunchBrowser=Launch browser
+ServerControl.Menu.File=File
+ServerControl.Menu.Settings=Settings...
+ServerControl.Menu.Exit=Exit
+ServerControl.Error={0} failed, please check server.log in {1}/logs for details. 
+ServerControl.Falied={0} failed
+ServerControl.Success={0} success
+greenstone.version=Version 3.2
+ServerSetting.SettingChanged=The new settings will be avaliable after the server restarted
Index: /greenstone3/trunk/resources/soap/localsite.wsdd
===================================================================
--- /greenstone3/trunk/resources/soap/localsite.wsdd	(revision 14125)
+++ /greenstone3/trunk/resources/soap/localsite.wsdd	(revision 14125)
@@ -0,0 +1,10 @@
+<deployment xmlns="http://xml.apache.org/axis/wsdd/"
+    xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"
+    xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">
+  <service name="localsite" style="message">
+    <parameter name="className" value="org.greenstone.gsdl3.SOAPServerlocalsite"/>
+    <parameter name="allowedMethods" value="process"/>
+    <parameter name="scope" value="application"/>
+  </service>
+</deployment>
+
Index: /greenstone3/trunk/resources/soap/site.wsdd.template
===================================================================
--- /greenstone3/trunk/resources/soap/site.wsdd.template	(revision 14125)
+++ /greenstone3/trunk/resources/soap/site.wsdd.template	(revision 14125)
@@ -0,0 +1,10 @@
+<deployment xmlns="http://xml.apache.org/axis/wsdd/"
+    xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"
+    xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance">
+  <service name="@siteuri@" style="message">
+    <parameter name="className" value="org.greenstone.gsdl3.SOAPServer@sitename@"/>
+    <parameter name="allowedMethods" value="process"/>
+    <parameter name="scope" value="application"/>
+  </service>
+</deployment>
+
Index: /greenstone3/trunk/resources/soap/undeploy-localsite.wsdd
===================================================================
--- /greenstone3/trunk/resources/soap/undeploy-localsite.wsdd	(revision 14125)
+++ /greenstone3/trunk/resources/soap/undeploy-localsite.wsdd	(revision 14125)
@@ -0,0 +1,3 @@
+<undeployment xmlns="http://xml.apache.org/axis/wsdd/">
+  <service name="localsite"/>
+</undeployment>
Index: /greenstone3/trunk/resources/soap/undeploy-site.wsdd.template
===================================================================
--- /greenstone3/trunk/resources/soap/undeploy-site.wsdd.template	(revision 14125)
+++ /greenstone3/trunk/resources/soap/undeploy-site.wsdd.template	(revision 14125)
@@ -0,0 +1,3 @@
+<undeployment xmlns="http://xml.apache.org/axis/wsdd/">
+  <service name="@siteuri@"/>
+</undeployment>
Index: /greenstone3/trunk/resources/tomcat/greenstone3.xml
===================================================================
--- /greenstone3/trunk/resources/tomcat/greenstone3.xml	(revision 14125)
+++ /greenstone3/trunk/resources/tomcat/greenstone3.xml	(revision 14125)
@@ -0,0 +1,8 @@
+<!-- set allowLinking to true if you want to use symlinks to files or directories outside the docBase directory -->
+<!-- set reloadable to false for a production version. if true, automatically reloads the webapp if it detects changes in classes or lib directories -->
+<!-- see http://tomcat.apache.org/tomcat-5.5-doc/config/context.html for more Context attributes -->
+<Context path="/greenstone3" 
+  docBase="@gsdl3webhome@" 
+  debug="1" reloadable="true" 
+  allowLinking="false">
+</Context>
Index: /greenstone3/trunk/resources/tomcat/server.xml
===================================================================
--- /greenstone3/trunk/resources/tomcat/server.xml	(revision 14125)
+++ /greenstone3/trunk/resources/tomcat/server.xml	(revision 14125)
@@ -0,0 +1,381 @@
+<!-- Example Server Configuration File -->
+<!-- Note that component elements are nested corresponding to their
+     parent-child relationships with each other -->
+
+<!-- A "Server" is a singleton element that represents the entire JVM,
+     which may contain one or more "Service" instances.  The Server
+     listens for a shutdown command on the indicated port.
+
+     Note:  A "Server" is not itself a "Container", so you may not
+     define subcomponents such as "Valves" or "Loggers" at this level.
+ -->
+
+<Server port="@shutdown-port@" shutdown="SHUTDOWN">
+
+  <!-- Comment these entries out to disable JMX MBeans support used for the 
+       administration web application -->
+  <Listener className="org.apache.catalina.core.AprLifecycleListener" />
+  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
+  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
+  <Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener"/>
+
+  <!-- Global JNDI resources -->
+  <GlobalNamingResources>
+
+    <!-- Test entry for demonstration purposes -->
+    <Environment name="simpleValue" type="java.lang.Integer" value="30"/>
+
+    <!-- Editable user database that can also be used by
+         UserDatabaseRealm to authenticate users -->
+    <Resource name="UserDatabase" auth="Container"
+              type="org.apache.catalina.UserDatabase"
+       description="User database that can be updated and saved"
+           factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
+          pathname="conf/tomcat-users.xml" />
+
+  </GlobalNamingResources>
+
+  <!-- A "Service" is a collection of one or more "Connectors" that share
+       a single "Container" (and therefore the web applications visible
+       within that Container).  Normally, that Container is an "Engine",
+       but this is not required.
+
+       Note:  A "Service" is not itself a "Container", so you may not
+       define subcomponents such as "Valves" or "Loggers" at this level.
+   -->
+
+  <!-- Define the Tomcat Stand-Alone Service -->
+  <Service name="Catalina">
+
+    <!-- A "Connector" represents an endpoint by which requests are received
+         and responses are returned.  Each Connector passes requests on to the
+         associated "Container" (normally an Engine) for processing.
+
+         By default, a non-SSL HTTP/1.1 Connector is established on port 8080.
+         You can also enable an SSL HTTP/1.1 Connector on port 8443 by
+         following the instructions below and uncommenting the second Connector
+         entry.  SSL support requires the following steps (see the SSL Config
+         HOWTO in the Tomcat 5 documentation bundle for more detailed
+         instructions):
+         * If your JDK version 1.3 or prior, download and install JSSE 1.0.2 or
+           later, and put the JAR files into "$JAVA_HOME/jre/lib/ext".
+         * Execute:
+             %JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA (Windows)
+             $JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA  (Unix)
+           with a password value of "changeit" for both the certificate and
+           the keystore itself.
+
+         By default, DNS lookups are enabled when a web application calls
+         request.getRemoteHost().  This can have an adverse impact on
+         performance, so you can disable it by setting the
+         "enableLookups" attribute to "false".  When DNS lookups are disabled,
+         request.getRemoteHost() will return the String version of the
+         IP address of the remote client.
+    -->
+
+    <!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
+    <Connector port="@port@" maxHttpHeaderSize="8192"
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false" redirectPort="8443" acceptCount="100"
+               connectionTimeout="20000" disableUploadTimeout="true" URIEncoding="UTF-8"/>
+    <!-- Note : To disable connection timeouts, set connectionTimeout value
+     to 0 -->
+	
+	<!-- Note : To use gzip compression you could set the following properties :
+	
+			   compression="on" 
+			   compressionMinSize="2048" 
+			   noCompressionUserAgents="gozilla, traviata" 
+			   compressableMimeType="text/html,text/xml"
+	-->
+
+    <!-- Define a SSL HTTP/1.1 Connector on port 8443 -->
+    <!--
+    <Connector port="8443" maxHttpHeaderSize="8192"
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false" disableUploadTimeout="true"
+               acceptCount="100" scheme="https" secure="true"
+               clientAuth="false" sslProtocol="TLS" />
+    -->
+
+    <!-- Define an AJP 1.3 Connector on port 8009 -->
+    <Connector port="8009" 
+               enableLookups="false" redirectPort="8443" protocol="AJP/1.3" />
+
+    <!-- Define a Proxied HTTP/1.1 Connector on port 8082 -->
+    <!-- See proxy documentation for more information about using this. -->
+    <!--
+    <Connector port="8082" 
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false" acceptCount="100" connectionTimeout="20000"
+               proxyPort="80" disableUploadTimeout="true" />
+    -->
+
+    <!-- An Engine represents the entry point (within Catalina) that processes
+         every request.  The Engine implementation for Tomcat stand alone
+         analyzes the HTTP headers included with the request, and passes them
+         on to the appropriate Host (virtual host). -->
+
+    <!-- You should set jvmRoute to support load-balancing via AJP ie :
+    <Engine name="Standalone" defaultHost="localhost" jvmRoute="jvm1">         
+    --> 
+         
+    <!-- Define the top level container in our container hierarchy -->
+    <Engine name="Catalina" defaultHost="localhost">
+
+      <!-- The request dumper valve dumps useful debugging information about
+           the request headers and cookies that were received, and the response
+           headers and cookies that were sent, for all requests received by
+           this instance of Tomcat.  If you care only about requests to a
+           particular virtual host, or a particular application, nest this
+           element inside the corresponding <Host> or <Context> entry instead.
+
+           For a similar mechanism that is portable to all Servlet 2.4
+           containers, check out the "RequestDumperFilter" Filter in the
+           example application (the source for this filter may be found in
+           "$CATALINA_HOME/webapps/examples/WEB-INF/classes/filters").
+
+           Request dumping is disabled by default.  Uncomment the following
+           element to enable it. -->
+      <!--
+      <Valve className="org.apache.catalina.valves.RequestDumperValve"/>
+      -->
+
+      <!-- Because this Realm is here, an instance will be shared globally -->
+
+      <!-- This Realm uses the UserDatabase configured in the global JNDI
+           resources under the key "UserDatabase".  Any edits
+           that are performed against this UserDatabase are immediately
+           available for use by the Realm.  -->
+      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
+             resourceName="UserDatabase"/>
+
+      <!-- Comment out the old realm but leave here for now in case we
+           need to go back quickly -->
+      <!--
+      <Realm className="org.apache.catalina.realm.MemoryRealm" />
+      -->
+
+      <!-- Replace the above Realm with one of the following to get a Realm
+           stored in a database and accessed via JDBC -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm"
+             driverName="org.gjt.mm.mysql.Driver"
+          connectionURL="jdbc:mysql://localhost/authority"
+         connectionName="test" connectionPassword="test"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm"
+             driverName="oracle.jdbc.driver.OracleDriver"
+          connectionURL="jdbc:oracle:thin:@ntserver:1521:ORCL"
+         connectionName="scott" connectionPassword="tiger"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm"
+             driverName="sun.jdbc.odbc.JdbcOdbcDriver"
+          connectionURL="jdbc:odbc:CATALINA"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!-- Define the default virtual host
+           Note: XML Schema validation will not work with Xerces 2.2.
+       -->
+      <Host name="localhost" appBase="webapps"
+       unpackWARs="true" autoDeploy="true"
+       xmlValidation="false" xmlNamespaceAware="false">
+	
+        <!-- Defines a cluster for this node,
+             By defining this element, means that every manager will be changed.
+             So when running a cluster, only make sure that you have webapps in there
+             that need to be clustered and remove the other ones.
+             A cluster has the following parameters:
+
+             className = the fully qualified name of the cluster class
+
+             name = a descriptive name for your cluster, can be anything
+
+             mcastAddr = the multicast address, has to be the same for all the nodes
+
+             mcastPort = the multicast port, has to be the same for all the nodes
+             
+             mcastBindAddr = bind the multicast socket to a specific address
+             
+             mcastTTL = the multicast TTL if you want to limit your broadcast
+             
+             mcastSoTimeout = the multicast readtimeout 
+
+             mcastFrequency = the number of milliseconds in between sending a "I'm alive" heartbeat
+
+             mcastDropTime = the number a milliseconds before a node is considered "dead" if no heartbeat is received
+
+             tcpThreadCount = the number of threads to handle incoming replication requests, optimal would be the same amount of threads as nodes 
+
+             tcpListenAddress = the listen address (bind address) for TCP cluster request on this host, 
+                                in case of multiple ethernet cards.
+                                auto means that address becomes
+                                InetAddress.getLocalHost().getHostAddress()
+
+             tcpListenPort = the tcp listen port
+
+             tcpSelectorTimeout = the timeout (ms) for the Selector.select() method in case the OS
+                                  has a wakup bug in java.nio. Set to 0 for no timeout
+
+             printToScreen = true means that managers will also print to std.out
+
+             expireSessionsOnShutdown = true means that 
+
+             useDirtyFlag = true means that we only replicate a session after setAttribute,removeAttribute has been called.
+                            false means to replicate the session after each request.
+                            false means that replication would work for the following piece of code: (only for SimpleTcpReplicationManager)
+                            <%
+                            HashMap map = (HashMap)session.getAttribute("map");
+                            map.put("key","value");
+                            %>
+             replicationMode = can be either 'pooled', 'synchronous' or 'asynchronous'.
+                               * Pooled means that the replication happens using several sockets in a synchronous way. Ie, the data gets replicated, then the request return. This is the same as the 'synchronous' setting except it uses a pool of sockets, hence it is multithreaded. This is the fastest and safest configuration. To use this, also increase the nr of tcp threads that you have dealing with replication.
+                               * Synchronous means that the thread that executes the request, is also the
+                               thread the replicates the data to the other nodes, and will not return until all
+                               nodes have received the information.
+                               * Asynchronous means that there is a specific 'sender' thread for each cluster node,
+                               so the request thread will queue the replication request into a "smart" queue,
+                               and then return to the client.
+                               The "smart" queue is a queue where when a session is added to the queue, and the same session
+                               already exists in the queue from a previous request, that session will be replaced
+                               in the queue instead of replicating two requests. This almost never happens, unless there is a 
+                               large network delay.
+        -->             
+        <!--
+            When configuring for clustering, you also add in a valve to catch all the requests
+            coming in, at the end of the request, the session may or may not be replicated.
+            A session is replicated if and only if all the conditions are met:
+            1. useDirtyFlag is true or setAttribute or removeAttribute has been called AND
+            2. a session exists (has been created)
+            3. the request is not trapped by the "filter" attribute
+
+            The filter attribute is to filter out requests that could not modify the session,
+            hence we don't replicate the session after the end of this request.
+            The filter is negative, ie, anything you put in the filter, you mean to filter out,
+            ie, no replication will be done on requests that match one of the filters.
+            The filter attribute is delimited by ;, so you can't escape out ; even if you wanted to.
+
+            filter=".*\.gif;.*\.js;" means that we will not replicate the session after requests with the URI
+            ending with .gif and .js are intercepted.
+            
+            The deployer element can be used to deploy apps cluster wide.
+            Currently the deployment only deploys/undeploys to working members in the cluster
+            so no WARs are copied upons startup of a broken node.
+            The deployer watches a directory (watchDir) for WAR files when watchEnabled="true"
+            When a new war file is added the war gets deployed to the local instance,
+            and then deployed to the other instances in the cluster.
+            When a war file is deleted from the watchDir the war is undeployed locally 
+            and cluster wide
+        -->
+        
+        <!--
+        <Cluster className="org.apache.catalina.cluster.tcp.SimpleTcpCluster"
+                 managerClassName="org.apache.catalina.cluster.session.DeltaManager"
+                 expireSessionsOnShutdown="false"
+                 useDirtyFlag="true"
+                 notifyListenersOnReplication="true">
+
+            <Membership 
+                className="org.apache.catalina.cluster.mcast.McastService"
+                mcastAddr="228.0.0.4"
+                mcastPort="45564"
+                mcastFrequency="500"
+                mcastDropTime="3000"/>
+
+            <Receiver 
+                className="org.apache.catalina.cluster.tcp.ReplicationListener"
+                tcpListenAddress="auto"
+                tcpListenPort="4001"
+                tcpSelectorTimeout="100"
+                tcpThreadCount="6"/>
+
+            <Sender
+                className="org.apache.catalina.cluster.tcp.ReplicationTransmitter"
+                replicationMode="pooled"
+                ackTimeout="15000"/>
+
+            <Valve className="org.apache.catalina.cluster.tcp.ReplicationValve"
+                   filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
+                   
+            <Deployer className="org.apache.catalina.cluster.deploy.FarmWarDeployer"
+                      tempDir="/tmp/war-temp/"
+                      deployDir="/tmp/war-deploy/"
+                      watchDir="/tmp/war-listen/"
+                      watchEnabled="false"/>
+                      
+            <ClusterListener className="org.apache.catalina.cluster.session.ClusterSessionListener"/>
+        </Cluster>
+        -->        
+
+
+
+        <!-- Normally, users must authenticate themselves to each web app
+             individually.  Uncomment the following entry if you would like
+             a user to be authenticated the first time they encounter a
+             resource protected by a security constraint, and then have that
+             user identity maintained across *all* web applications contained
+             in this virtual host. -->
+        <!--
+        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
+        -->
+
+        <!-- Access log processes all requests for this virtual host.  By
+             default, log files are created in the "logs" directory relative to
+             $CATALINA_HOME.  If you wish, you can specify a different
+             directory with the "directory" attribute.  Specify either a relative
+             (to $CATALINA_HOME) or absolute path to the desired directory.
+        -->
+        <!--
+        <Valve className="org.apache.catalina.valves.AccessLogValve"
+                 directory="logs"  prefix="localhost_access_log." suffix=".txt"
+                 pattern="common" resolveHosts="false"/>
+        -->
+
+        <!-- Access log processes all requests for this virtual host.  By
+             default, log files are created in the "logs" directory relative to
+             $CATALINA_HOME.  If you wish, you can specify a different
+             directory with the "directory" attribute.  Specify either a relative
+             (to $CATALINA_HOME) or absolute path to the desired directory.
+             This access log implementation is optimized for maximum performance,
+             but is hardcoded to support only the "common" and "combined" patterns.
+        -->
+        <!--
+        <Valve className="org.apache.catalina.valves.FastCommonAccessLogValve"
+                 directory="logs"  prefix="localhost_access_log." suffix=".txt"
+                 pattern="common" resolveHosts="false"/>
+        -->
+        <!-- Access log processes all requests for this virtual host.  By
+             default, log files are created in the "logs" directory relative to
+             $CATALINA_HOME.  If you wish, you can specify a different
+             directory with the "directory" attribute.  Specify either a relative
+             (to $CATALINA_HOME) or absolute path to the desired directory.
+             This access log implementation is optimized for maximum performance,
+             but is hardcoded to support only the "common" and "combined" patterns.
+
+             This valve use NIO direct Byte Buffer to asynchornously store the
+             log.
+        -->
+        <!--
+        <Valve className="org.apache.catalina.valves.ByteBufferAccessLogValve"
+                 directory="logs"  prefix="localhost_access_log." suffix=".txt"
+                 pattern="common" resolveHosts="false"/>
+        -->
+
+      </Host>
+
+    </Engine>
+
+  </Service>
+
+</Server>
Index: /greenstone3/trunk/resources/tomcat/setclasspath.bat
===================================================================
--- /greenstone3/trunk/resources/tomcat/setclasspath.bat	(revision 14125)
+++ /greenstone3/trunk/resources/tomcat/setclasspath.bat	(revision 14125)
@@ -0,0 +1,57 @@
+rem ---------------------------------------------------------------------------
+rem Set CLASSPATH and Java options
+rem
+rem $Id$
+rem ---------------------------------------------------------------------------
+
+rem Make sure prerequisite environment variables are set
+if not "%JAVA_HOME%" == "" goto gotJavaHome
+echo The JAVA_HOME environment variable is not defined
+echo This environment variable is needed to run this program
+goto exit
+:gotJavaHome
+if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
+if not exist "%JAVA_HOME%\bin\javaw.exe" goto noJavaHome
+if not exist "%JAVA_HOME%\bin\jdb.exe" goto noJavaHome
+if not exist "%JAVA_HOME%\bin\javac.exe" goto noJavaHome
+goto okJavaHome
+:noJavaHome
+echo The JAVA_HOME environment variable is not defined correctly
+echo This environment variable is needed to run this program
+echo NB: JAVA_HOME should point to a JDK not a JRE
+goto exit
+:okJavaHome
+
+if not "%BASEDIR%" == "" goto gotBasedir
+echo The BASEDIR environment variable is not defined
+echo This environment variable is needed to run this program
+goto exit
+:gotBasedir
+if exist "%BASEDIR%\bin\setclasspath.bat" goto okBasedir
+echo The BASEDIR environment variable is not defined correctly
+echo This environment variable is needed to run this program
+goto exit
+:okBasedir
+
+rem Set the default -Djava.endorsed.dirs argument
+set JAVA_ENDORSED_DIRS=%BASEDIR%\common\endorsed
+
+rem Set standard CLASSPATH
+rem Note that there are no quotes as we do not want to introduce random
+rem quotes into the CLASSPATH
+set CLASSPATH=%JAVA_HOME%\lib\tools.jar;%CLASSPATH%
+
+rem Set standard command for invoking Java.
+rem Note that NT requires a window name argument when using start.
+rem Also note the quoting as JAVA_HOME may contain spaces.
+set _RUNJAVA="%JAVA_HOME%\bin\java"
+set _RUNJAVAW="%JAVA_HOME%\bin\javaw"
+set _RUNJDB="%JAVA_HOME%\bin\jdb"
+set _RUNJAVAC="%JAVA_HOME%\bin\javac"
+
+goto end
+
+:exit
+exit /b 1
+
+:end
Index: /greenstone3/trunk/resources/tomcat/setclasspath.sh
===================================================================
--- /greenstone3/trunk/resources/tomcat/setclasspath.sh	(revision 14125)
+++ /greenstone3/trunk/resources/tomcat/setclasspath.sh	(revision 14125)
@@ -0,0 +1,87 @@
+#!/bin/sh
+# -----------------------------------------------------------------------------
+#  Set CLASSPATH and Java options
+#
+#  $Id$
+# -----------------------------------------------------------------------------
+
+# First clear out the user classpath
+# gs3 - we need to set classpath
+CLASSPATH=$CLASSPATH
+
+# Make sure prerequisite environment variables are set
+if [ -z "$JAVA_HOME" -a -z "$JRE_HOME" ]; then
+  echo "Neither the JAVA_HOME nor the JRE_HOME environment variable is defined"
+  echo "At least one of these environment variable is needed to run this program"
+  exit 1
+fi
+if [ -z "$JAVA_HOME" -a "$1" = "debug" ]; then
+  echo "JAVA_HOME should point to a JDK in order to run in debug mode."
+  exit 1
+fi
+if [ -z "$JRE_HOME" ]; then
+  JRE_HOME="$JAVA_HOME"
+fi
+
+# If we're running under jdb, we need a full jdk.
+if [ "$1" = "debug" -o "$1" = "javac" ] ; then
+  if [ "$os400" = "true" ]; then
+    if [ ! -x "$JAVA_HOME"/bin/java -o ! -x "$JAVA_HOME"/bin/javac ]; then
+      echo "The JAVA_HOME environment variable is not defined correctly"
+      echo "This environment variable is needed to run this program"
+      echo "NB: JAVA_HOME should point to a JDK not a JRE"
+      exit 1
+    fi
+  else
+    if [ ! -x "$JAVA_HOME"/bin/java -o ! -x "$JAVA_HOME"/bin/jdb -o ! -x "$JAVA_HOME"/bin/javac ]; then
+      echo "The JAVA_HOME environment variable is not defined correctly"
+      echo "This environment variable is needed to run this program"
+      echo "NB: JAVA_HOME should point to a JDK not a JRE"
+      exit 1
+    fi
+  fi
+fi
+if [ -z "$BASEDIR" ]; then
+  echo "The BASEDIR environment variable is not defined"
+  echo "This environment variable is needed to run this program"
+  exit 1
+fi
+if [ ! -x "$BASEDIR"/bin/setclasspath.sh ]; then
+  if $os400; then
+    # -x will Only work on the os400 if the files are:
+    # 1. owned by the user
+    # 2. owned by the PRIMARY group of the user
+    # this will not work if the user belongs in secondary groups
+    eval
+  else
+    echo "The BASEDIR environment variable is not defined correctly"
+    echo "This environment variable is needed to run this program"
+    exit 1
+  fi
+fi
+
+# Set the default -Djava.endorsed.dirs argument
+JAVA_ENDORSED_DIRS="$BASEDIR"/common/endorsed
+
+# Set standard CLASSPATH
+if [ "$1" = "debug" -o "$1" = "javac" ] ; then
+  CLASSPATH="$JAVA_HOME"/lib/tools.jar:$CLASSPATH
+fi
+
+# OSX hack to CLASSPATH
+JIKESPATH=
+if [ `uname -s` = "Darwin" ]; then
+  OSXHACK="/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Classes"
+  if [ -d "$OSXHACK" ]; then
+    for i in "$OSXHACK"/*.jar; do
+      JIKESPATH="$JIKESPATH":"$i"
+    done
+  fi
+fi
+
+# Set standard commands for invoking Java.
+  _RUNJAVA="$JRE_HOME"/bin/java
+if [ "$os400" != "true" ]; then
+  _RUNJDB="$JAVA_HOME"/bin/jdb
+fi
+_RUNJAVAC="$JAVA_HOME"/bin/javac
Index: /greenstone3/trunk/resources/xml/collectionConfig.xml
===================================================================
--- /greenstone3/trunk/resources/xml/collectionConfig.xml	(revision 14125)
+++ /greenstone3/trunk/resources/xml/collectionConfig.xml	(revision 14125)
@@ -0,0 +1,67 @@
+<collectionConfig xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat" xmlns:xslt="http://www.w3.org/1999/XSL/Transform">>
+  <metadataList>
+    <!-- email address of collection creator -->
+    <metadata name="creator"></metadata>
+  </metadataList>
+  <displayItemList>
+    <!-- Display name of collection -->
+    <displayItem name='name' lang='en'></displayItem>
+    <!-- Display description of collection -->
+    <displayItem name='description' lang='en'></displayItem>
+    <!-- Icon name for collection home page -->
+    <displayItem name='icon' lang='en'></displayItem>
+    <!-- Icon name for library home page -->
+    <displayItem name='smallicon' lang='en'></displayItem>
+  </displayItemList>
+  <recognise>
+    <docType name="HTML"/>
+    <docType name="Text"/>
+    <docType name="Metadata"/>
+    <docType name="JPEG"/>
+  </recognise>
+  <search type="mg" name="mgsearch">
+    <index name="doctext">
+      <field>text</field>
+      <level>document</level>
+      <displayItem name='name' lang="en">entire documents</displayItem>
+      <displayItem name='name' lang="fr">documents entiers</displayItem>
+      <displayItem name='name' lang="es">documentos enteros</displayItem>
+    </index>
+    <!-- section level text index -->
+    <!-- <index name="sectext">
+    <field>text</field>
+    <level>section</level>
+      <displayItem name='name' lang="en">chapters</displayItem>
+      <displayItem name='name' lang="fr">chapitres</displayItem>
+      <displayItem name='name' lang="es">capÃ­tulos</displayItem>
+    </index>-->
+    <!-- section level title index -->
+    <!--<index name="sectitle">
+      <field>Title</field>
+      <level>section</level>
+      <displayItem name='name' lang="en">section titles</displayItem>
+      <displayItem name='name' lang="fr">titres des sections</displayItem>
+      <displayItem name='name' lang="es">tÃ­tulos de las secciones</displayItem>
+    </index>-->
+    <!-- default format -->
+    <format>
+      <gsf:template match="documentNode"><td valign='top'><gsf:link><gsf:icon/></gsf:link></td><td><gsf:metadata name='Title'/></td></gsf:template>
+    </format>
+  </search>
+  <browse>
+    <classifier name="CLTit" type="AZList" horizontalAtTop='true'>
+      <field>Title</field>
+      <sort>Title</sort>
+      <displayItem name='name' lang='en'>Titles</displayItem>
+    </classifier>
+  </browse>
+  <display>
+    <format>
+      <!-- set to true if have cover images -->
+      <gsf:option name="coverImages" value="false"/>
+      <!-- set to true if have sectioned documents -->
+      <gsf:option name="documentTOC" value="false"/>
+    </format>
+  </display>
+</collectionConfig>
+
Index: /greenstone3/trunk/src/java/org/greenstone/admin/Configuration.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/admin/Configuration.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/admin/Configuration.java	(revision 14125)
@@ -0,0 +1,132 @@
+/**
+ *#########################################################################
+ * Configuration
+ * A component of the GAI application, part of the Greenstone digital
+ * library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * <BR><BR>
+ *
+ * Copyright (C) 1999 New Zealand Digital Library Project
+ *
+ * <BR><BR>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * <BR><BR>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * <BR><BR>
+ *
+ * You should have received a copy of the 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 org.greenstone.admin;
+
+import java.awt.Color;
+import java.util.Locale;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+
+// eventually this class will hold configuration settings from a config file. For now, lets use static info
+// loosely copied from Gatherer Configuration
+public class Configuration {
+    
+    static private Hashtable hash = null;
+
+    /** The first of three patterns used during tokenization, this pattern handles a comma separated list. */
+    static final private String TOKENIZER_PATTERN1 = " ,\n\t";
+    /** The second of three patterns used during tokenization, this pattern handles an underscore separated list. */
+    static final private String TOKENIZER_PATTERN2 = "_\n\t";
+    /** The last of three patterns used during tokenization, this pattern handles an comma separated list containing spaces. */
+    static final private String TOKENIZER_PATTERN3 = ",\n\t";
+
+    public Configuration() {
+	
+	hash = new Hashtable();
+	
+	
+	// load up all the initial stuff
+	hash.put("admin.log", "true");
+	hash.put("admin.conf", "true");
+	hash.put("admin.ext", "true");
+	hash.put("admin.monitor", "true");
+	hash.put("coloring.workspace_selection_foreground", "0, 0, 0");
+	hash.put("coloring.workspace_selection_background", "176, 208, 176");
+	hash.put("coloring.table_noneditable_background", "255, 255, 255");
+	hash.put("coloring.table_editable_background", "255, 255, 255");
+	hash.put("coloring.collection_tree_background", "224, 240, 224");
+	hash.put("coloring.collection_tree_foreground", "0, 0, 0");
+	hash.put("coloring.workspace_tree_foreground", "0, 0, 0");
+	hash.put("coloring.workspace_tree_background", "218, 237, 252");
+	hash.put("coloring.workspace_heading_background", "128, 180, 216");
+	hash.put("coloring.workspace_heading_foreground", "0, 0, 0");
+	
+    }
+
+    /** Retrieve whether the named property is set or not */
+    static public boolean get(String property) {
+	String value = (String)hash.get(property);
+	return (value != null && value.equalsIgnoreCase("true"));
+    }
+    
+    /** Retrieve the value of the named property as a String */
+    static public String getString(String property) {
+	return (String)hash.get(property);
+    }
+
+    /** Retrieve the value of the named property as a Locale. */
+    static public Locale getLocale(String property) {
+	Locale result = Locale.getDefault();
+	try {
+	    String raw = (String) hash.get(property);
+	    if (raw==null) {
+		return result;
+	    }
+	    // Locale is a underscore separated code.
+	    StringTokenizer tokenizer = new StringTokenizer(raw, TOKENIZER_PATTERN2);
+	    String language = tokenizer.nextToken();
+	    if(tokenizer.hasMoreTokens()) {
+		String country = tokenizer.nextToken();
+		result = new Locale(language, country);
+	    }
+	    else {
+		result = new Locale(language);
+	    }
+	}
+	catch(Exception error) {
+	    error.printStackTrace();
+	}
+	return result;
+    }
+    
+    /** Retrieve the value of the named property as a Color. */
+    static public Color getColor(String property) {
+	Color result = Color.white; // Default
+	String raw = (String)hash.get(property);
+	if (raw == null || raw.equals("")) {
+	    return result;
+	}
+	try {
+	    // Color is a RGB triplet list, comma separated (also remove whitespace)
+	    StringTokenizer tokenizer = new StringTokenizer(raw, TOKENIZER_PATTERN1);
+	    int red = Integer.parseInt(tokenizer.nextToken());
+	    int green = Integer.parseInt(tokenizer.nextToken());
+	    int blue = Integer.parseInt(tokenizer.nextToken());
+	    result = new Color(red, green, blue);
+	}
+	catch(Exception error) {
+	    error.printStackTrace();
+	}
+	return result;
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/admin/GAI.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/admin/GAI.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/admin/GAI.java	(revision 14125)
@@ -0,0 +1,115 @@
+/**
+ *#########################################################################
+ *
+ * A component of the Greenstone Administrator Interface, part of the Greenstone digital
+ * library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Chi-Yu Huang, Greenstone Digital Library, University of Waikato
+ *
+ * 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 org.greenstone.admin;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.lang.*;
+import java.net.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.plaf.*;
+import javax.swing.text.*;
+
+import org.greenstone.gsdl3.util.Dictionary;
+import org.greenstone.admin.gui.SetServerPane;
+
+/** Containing the top-level "core" for the GAI(Greenstone Administrator
+ * Interface) this class is the common core for the GAI application and 
+ * applet. It first parses the command line arguments, preparing to update 
+ * the configuration as required. Next it loads several important support 
+ * classes such as the Configuration and Dictionary. Finally it creates the 
+ * other important managers and sends them on their way.
+ * @author Chi-Yu Huang, Greenstone Digital Library, University of Waikato
+ * @version ###
+ */
+public class GAI
+{
+    public static Dimension screen_size = Toolkit.getDefaultToolkit().getScreenSize();
+    public static String gsdl3_src_home;
+    public static String gsdl3_web_home;
+    public static String tomcat_home;
+    
+    public static File build_properties_file;
+
+    public static String images_path;
+    /** A public reference to the GAIManager. */
+    static public GAIManager ga_man;
+
+    /** a public reference to the Dictionary */
+    static public Dictionary dictionary = null;
+    
+    public GAI(String gsdl3_src_home, String gsdl3_web_home)
+    {
+	this.gsdl3_src_home = gsdl3_src_home;
+	this.gsdl3_web_home = gsdl3_web_home;
+	
+	// set up the Configuration
+	new Configuration();
+	
+	// Read Dictionary
+	this.dictionary = new Dictionary("gai", Configuration.getLocale("general.locale"));
+	this.build_properties_file = new File(this.gsdl3_src_home, "build.properties");
+	// this may change if using preinstalled tomcat
+	this.tomcat_home = this.gsdl3_src_home+File.separatorChar+"packages"+File.separatorChar+"tomcat";
+	
+	// should come from classpath ??
+	this.images_path = this.gsdl3_src_home+File.separatorChar+"resources"+File.separatorChar+"images"+File.separatorChar;
+	// start the GAIManager
+	ga_man  = new GAIManager(screen_size);
+	ga_man.display();
+
+    }
+    
+    public static void main (String[] args){
+	// A serious hack, but its good enough to stop crappy 'Could not
+        // lock user prefs' error messages.  Thanks to Walter Schatz from
+        // the java forums.
+        System.setProperty("java.util.prefs.syncInterval","2000000");
+
+	if (args.length != 2) {
+	    System.err.println("Usage: java org.greenstone.admin.GAI <gsdl3 src home> <gsdl3 web home>");
+	    System.exit(1);
+	}
+	
+	File gsdl3_src_dir = new File(args[0]);
+	File gsdl3_web_dir = new File(args[1]);
+	if (!gsdl3_src_dir.isDirectory() || !gsdl3_web_dir.isDirectory()) {
+	    System.err.println("Usage: java org.greenstone.admin.GAI <gsdl3 src home> <gsdl3 web home>");
+	    System.err.println("src or web directory does not exist!");
+	    System.exit(1);
+	}
+	
+	GAI gai = new GAI(args[0], args[1]);
+
+    }
+
+}
+
+
Index: /greenstone3/trunk/src/java/org/greenstone/admin/GAIFirstSettingFrame.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/admin/GAIFirstSettingFrame.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/admin/GAIFirstSettingFrame.java	(revision 14125)
@@ -0,0 +1,218 @@
+/**
+ *#########################################################################
+ *
+ * A component of the GAI application, part of the Greenstone digital
+ * library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * <BR><BR>
+ *
+ * Author: Chi-Yu Huang, Greenstone Digital Library, University of Waikato
+ * Date: 03.2005
+ *
+ * <BR><BR>
+ *
+ * Copyright (C) 1999 New Zealand Digital Library Project
+ *
+ * <BR><BR>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * <BR><BR>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * <BR><BR>
+ *
+ * You should have received a copy of the 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 intended to confirm the initial user's setting about
+ * the Tomcat server and MySQL server they would like to run GSDL3 with
+ */
+package org.greenstone.admin;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.lang.Object;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.tree.*;
+
+import org.greenstone.core.ParsingProgress;
+import org.greenstone.admin.gui.SetServerPane;
+import org.greenstone.admin.GAI;
+
+/** The initial setting pane is to request the user to input the preferred 
+ *  Tomcat and Mysql server,they would like to run GSDL3 with
+ *  @author Chi-Yu Huang, Greenstone Digital Library, University of Waikato
+ *  @version
+ */
+public class GAIFirstSettingFrame
+    extends JFrame
+    implements ActionListener {
+
+    public static Dimension screen_size = Toolkit.getDefaultToolkit().getScreenSize();
+   
+    /* This pane is to inform the user to set up the tomcat and mysql server 
+     * if they are the first time run GAI, if the user doen't want to set up
+     * the installation will be based on the gsdl3 default value*/
+    protected JScrollPane setting_message_pane = null;
+    protected JPanel first_setting_pane = null;
+    protected JPanel main_pane = null;
+    protected JTextArea first_setting_message = null;
+    protected JButton fset_yes_button = null;
+    protected JButton fset_no_button = null;
+    protected JPanel button_pane = null;
+    protected JPanel control_pane = null;
+    
+    public boolean setting_confirm = false;
+    
+    /** The various sizes for the screen layout*/
+    static private Dimension MIN_SIZE = new Dimension( 90,  90);
+    static private Dimension LIST_SIZE  = new Dimension(200, 450);
+    static private Dimension DIALOG_SIZE = new Dimension (400,300);
+    static private Dimension TABLE_SIZE = new Dimension(500,200);
+    static final Dimension SIZE = new Dimension(400,75);						   
+    
+    //Constructor
+    public GAIFirstSettingFrame() {
+	super();
+
+	this.setDefaultCloseOperation(EXIT_ON_CLOSE);
+	this.setSize(DIALOG_SIZE);
+	this.setTitle("First time setting Tomcat/MYSQL Server");
+
+	// create all the control button panes
+	button_pane  = new JPanel();
+
+	//First time running button
+	FirstSetYesButtonListener fsybl = new FirstSetYesButtonListener();
+	FirstSetNoButtonListener fsnbl = new FirstSetNoButtonListener();
+	
+	// ImagesIcon for the buttons
+	ImageIcon setYesButtonIcon = new ImageIcon(GAI.images_path + "refresh.gif");
+	ImageIcon setNoButtonIcon = new ImageIcon(GAI.images_path + "exit.gif");
+	
+	fset_yes_button = new JButton("Yes", setYesButtonIcon);
+	fset_yes_button.addActionListener(fsybl);
+	fset_yes_button.setMnemonic(KeyEvent.VK_S);
+	fset_yes_button.setToolTipText("Click this button to Set up the Tomcat/MYSQL server");
+	fset_yes_button.setEnabled(false);
+	fset_no_button = new JButton("No", setNoButtonIcon);
+	fset_no_button.addActionListener(fsnbl);
+	fset_no_button.setEnabled(false);
+	fset_no_button.setMnemonic(KeyEvent.VK_N);
+	fset_no_button.setToolTipText("Click this button to skip the First time Tomcat/MYSQL server setting");
+	
+	//First time running setting buttons
+	fsybl = null;
+	fsnbl = null;
+	display();
+    }
+
+    /** Any implementation of ActionListener requires this method so that when an 
+     **action is performed the appropriate effect can occur.*/
+    public void actionPerformed(ActionEvent event) {
+    }
+
+    /** This method is callsed to actually layout the components.*/
+    public void display() {
+	//KeyListenerImpl key_listener = new KeyListenerImpl();
+	//MouseListenerImpl mouse_listener = new MouseListenerImpl();
+	//this.addKeyListener(key_listener);
+
+	first_setting_message = new JTextArea();
+	first_setting_message.setEditable(false);
+	first_setting_message.setLineWrap(true);
+	
+	first_setting_message.setText("If you are about the first time to run GAI, you can set up " +
+				      "your own TOMCAT/MYSQL server. Otherwise, your GSDL3 " +
+				      "will be installed with the TOMCAT/MYSQL setting come " +
+				      "with the package. You may change the setting later on.");
+
+	first_setting_message.setFont(new Font("Arial", Font.BOLD, 14));
+	
+	setting_message_pane = new JScrollPane(first_setting_message);
+	
+	// The pane to store setting_message_pane
+	first_setting_pane = new JPanel();
+	first_setting_pane.setBorder(BorderFactory.createEmptyBorder(5,5,20,5));
+	first_setting_pane.setLayout (new BorderLayout());
+	first_setting_pane.add(setting_message_pane, BorderLayout.CENTER);
+
+	// Button Control Layout 
+	fset_yes_button.setEnabled(true);
+	fset_no_button.setEnabled(true);
+
+	button_pane.setLayout (new GridLayout(1,2));
+	button_pane.add(fset_yes_button);
+	button_pane.add(fset_no_button);
+
+	control_pane = new JPanel();
+	control_pane.setBorder(BorderFactory.createLoweredBevelBorder());
+	control_pane.setLayout(new BorderLayout());
+	control_pane.add(new JLabel("Do you want to set up your own running Tomcat/Mysql Servers?"), BorderLayout.CENTER);
+	control_pane.add(button_pane, BorderLayout.SOUTH);
+			 
+	main_pane = (JPanel) getContentPane();
+	//main_pane.setBorder(BorderFactory.createLoweredBevelBorder());
+	main_pane.setLayout (new BorderLayout());
+	main_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	main_pane.add(first_setting_pane,BorderLayout.CENTER);
+	main_pane.add(control_pane, BorderLayout.SOUTH);
+	main_pane.setBackground(Configuration.getColor("coloring.workspace_selection_background"));
+	main_pane.setForeground(Configuration.getColor("coloring.workspace_selection_foreground"));
+
+	// Center and display
+	Dimension screen_size = Toolkit.getDefaultToolkit().getScreenSize();
+	setLocation((screen_size.width - SIZE.width) / 2,
+		    (screen_size.height - SIZE.height) / 2);
+	setVisible(true);
+    }
+    
+    public boolean checkSettingConfirm(){
+	return setting_confirm;
+    }
+
+    public void destroy() {
+    }
+        
+    /** This class serves as the listener for actions on the build button.*/
+    private class FirstSetYesButtonListener
+	implements ActionListener {
+	/** If you want to give up the change you have made to the build properties 
+	 *  file before you save the change,  This button is to reload the log file 
+	 *  whenever user want to */
+	public void actionPerformed(ActionEvent event) {
+	    SetServerPane set_server_pane = new SetServerPane ();
+	    set_server_pane.display();
+	    //disable the GAIFirstSettingFrame
+	    setVisible (false);
+	    setting_confirm = true;
+	}
+    }
+    private class FirstSetNoButtonListener
+	implements ActionListener {
+	// Exit the Adminstration tool 
+	public void actionPerformed(ActionEvent event) {
+	    setting_confirm = false;
+	    setVisible (false);
+	    //return setting_confirm;
+	    if (!setting_confirm) {
+		GAIManager gai = new GAIManager(screen_size);
+	    }
+	}
+    }
+}
+       
+
Index: /greenstone3/trunk/src/java/org/greenstone/admin/GAIManager.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/admin/GAIManager.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/admin/GAIManager.java	(revision 14125)
@@ -0,0 +1,353 @@
+/**
+ *#########################################################################
+ *
+ * A component of the Administration Tool (GAI) application, part of the 
+ * Greenstone digital library suite 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.
+ *
+ * Author: Chi-Yu Huang, Greenstone Digital Library, University of Waikato
+ *
+ *########################################################################
+ */
+
+package org.greenstone.admin;
+
+import org.greenstone.admin.GAI;
+import org.greenstone.admin.gui.TabbedPane;
+import org.greenstone.admin.gui.MenuBar;
+import org.greenstone.admin.gui.LogPane;
+import org.greenstone.admin.gui.ConfPane;
+
+//import java AWT classes
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.plaf.*;
+
+public class GAIManager 
+    extends JFrame 
+    implements ActionListener, ChangeListener{
+    
+    private Dimension size = null;
+    // The ConfPane contains the configuration details of Greenstone III build and installation
+    public ConfPane conf_pane = null;
+    // The LogPane contains the log details for Tomcat Server used by gsdl3
+    public LogPane log_pane = null;
+    // Not designed yet
+    public JPanel ext_pane = null;
+    // Not designed yet
+    public JPanel monitor_pane = null;
+       
+    static public ImageIcon CONF_ICON = null; 
+    static public ImageIcon EXT_ICON = null; 
+    static public ImageIcon MONITOR_ICON = null; 
+    static public ImageIcon LOG_ICON = null; 
+    
+    // Create a menu bar in the main Pane
+    public MenuBar menu_bar = null;
+
+    // HelpFrame
+    
+    private JPanel previous_pane = null;
+    private JPanel content_pane = null;
+    private JTabbedPane tab_pane = null;
+
+    /** A threaded tab changer to try and avoid NPE on exit. */
+    private TabUpdater tab_updater = null;
+    
+    //Contructor
+    public GAIManager(Dimension size){
+	super();
+	this.size = size;
+	this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+	this.setTitle("GreenStone 3 Administration Tool");
+	/* Add a focus listener to ourselves. Thus if we gain focus when a Modal Dialog should 
+	 * instead have it, we can try to bring the modal dialog to the front*/
+	//this.addFocusListener(new GAIGUIFocusListener());	
+	//display();
+    }
+
+    private class GAIGUIFocusListener
+	extends FocusAdapter {
+	public void focusGained(FocusEvent e) {
+	    /*  if (ModalDialog.current_modal != null) {
+		ModalDialog.current_modal.makeVisible();
+		ModalDialog.current_modal.toFront();
+		}*/
+	}
+    }
+
+   public void display(){
+	CONF_ICON = new ImageIcon (GAI.images_path + "create.gif");
+	EXT_ICON = new ImageIcon (GAI.images_path + "information.gif");	
+	MONITOR_ICON = new ImageIcon (GAI.images_path + "zoom.gif");
+	LOG_ICON = new ImageIcon (GAI.images_path + "history.gif");
+	content_pane = (JPanel) this.getContentPane();
+
+	try {
+	    this.setSize(size);
+	    //create a menuBar
+	    menu_bar = new MenuBar(new MenuListenerImpl());
+	    this.setJMenuBar(menu_bar);
+	    
+	    //Create the tabbed pane and put it in the center
+	    tab_pane = new JTabbedPane();
+	    tab_pane.addChangeListener(this);
+	    
+	    //set up the Configuration Pane
+	    if (Configuration.get("admin.conf")){
+		conf_pane = new ConfPane();
+		conf_pane.display();
+		tab_pane.addTab("Configuration", CONF_ICON, conf_pane);
+		tab_pane.setEnabledAt(tab_pane.indexOfComponent(conf_pane),Configuration.get("admin.conf"));
+	    }
+	    	    
+	    //set up the ext Pane
+	    if (Configuration.get("admin.ext")){
+		ext_pane = new JPanel();
+		//ext_pane.display();
+		tab_pane.addTab("Exts", EXT_ICON, ext_pane);
+		tab_pane.setEnabledAt(tab_pane.indexOfComponent(ext_pane),Configuration.get("admin.ext"));
+	    }
+	    	    
+	    //set up the Monitor Pane
+	    if (Configuration.get("admin.monitor")){
+		monitor_pane = new JPanel();
+		//monitor_pane.display();
+		tab_pane.addTab("Monitor", MONITOR_ICON, monitor_pane);
+		tab_pane.setEnabledAt(tab_pane.indexOfComponent(monitor_pane),Configuration.get("admin.monitor"));
+	    }
+
+	    //set up the Log Pane
+	    if (Configuration.get("admin.log")){
+		log_pane = new LogPane();
+		log_pane.display();
+		tab_pane.addTab("Log", LOG_ICON, log_pane);
+		tab_pane.setEnabledAt(tab_pane.indexOfComponent(log_pane),Configuration.get("admin.log"));
+	    }   
+	    content_pane.setLayout(new BorderLayout());
+	    content_pane.add(tab_pane, BorderLayout.CENTER);
+	    pack();
+	    setVisible(true);
+	} catch (Exception e){
+	    e.printStackTrace();
+	    System.exit(1);
+	}
+    }
+
+    /** Any implementation of <i>ActionListener</i> must include this method so that we can be informed 
+     *  when an action has occured. In this case we are listening to actions from the menu-bar, and should 
+     *  react appropriately.
+     * @param event An <strong>ActionEvent</strong> containing information about the action that has occured.
+     */
+    
+    public void actionPerformed (ActionEvent event){
+	Object esrc = event.getSource();
+	if (esrc == menu_bar.file_exit){
+	    if (conf_pane.configurationChanged()) {
+		// prompt users for save
+		int result = JOptionPane.showConfirmDialog((Component) null, "The Configuration files have been changed, do you want to save the change", "Save Confirmation", JOptionPane.YES_NO_OPTION);
+		if ( result == JOptionPane.YES_OPTION) {
+		    conf_pane.save();	
+		} 
+	    }
+	    exit();
+	}
+	else if (esrc == menu_bar.file_save){
+	    /* sliently and Globally save Project and Site configuration*/
+	    conf_pane.save();
+	}
+	else if (esrc == menu_bar.help_conf){
+	}
+	else if (esrc == menu_bar.help_ext){
+	} 
+	else if (esrc == menu_bar.help_monitor){
+	}
+	else if (esrc == menu_bar.help_log){
+	}
+	else if (esrc == menu_bar.help_about) {
+	}
+    }
+    
+    
+    public void destory (){
+	// Destroying create pane ensures the latest log has been closed
+	//if (status_pane != null) {
+	//}
+    }
+    /**Overridden from JFrame so we can exit safely when window is closed 
+     *(or destroyed). @param event A <strong>WindowEvent</strong> containing 
+     *information about the event that fired this call.
+     */
+    protected void processWindowEvent(WindowEvent event) {
+	if(event.getID() == WindowEvent.WINDOW_CLOSING) {
+	    exit();
+	}
+    }
+
+
+    /** Listens to actions upon the menu bar, and if it detects a click over 
+     *the help menu brings the help window to the front if it has become hidden.
+     */
+    private class MenuListenerImpl
+	implements MenuListener {
+	public void menuCanceled (MenuEvent e) {
+	}
+	
+	public void menuDeselected (MenuEvent e){
+	}
+	
+	public void menuSelected (MenuEvent e){
+	    if (e.getSource() == menu_bar.file_exit) {
+		exit();
+	    }
+	  
+	    if (e.getSource() == menu_bar.help){
+		if (menu_bar.help.isSelected()){
+		    menu_bar.help.doClick(10);
+		}
+	    }
+	}
+    }
+
+
+    /** This method ensures that all the things needing saving 
+     *  are saved before GAIManager.exit() is called.
+     */
+    public void exit() {
+	System.exit(0);
+    }
+
+
+    /** Any implementation of ChangeListener must include this method 
+     **so we can be informed when the state of one of the registered 
+     **objects changes. In this case we are listening to view changes 
+     **within the tabbed pane.
+     * @param event A ChangeEvent containing information about the event that fired this call.
+     */
+    public void stateChanged(ChangeEvent event) {
+	if(previous_pane != null) {
+	}
+	
+	//menu_bar.tabSelected(tab_pane.getSelectedIndex());
+	int selected_index = tab_pane.getSelectedIndex();
+	if (selected_index == tab_pane.indexOfComponent(log_pane)) {
+	    log_pane.gainFocus();
+	}
+	else if (selected_index == tab_pane.indexOfComponent(conf_pane)) {
+	    conf_pane.gainFocus();
+	}
+	previous_pane = (JPanel) tab_pane.getSelectedComponent();
+    }
+    
+    public void modeChanged (int mode){
+	if (log_pane != null){
+	    log_pane.modeChanged(mode);
+	}
+	if (conf_pane !=null) {
+	    conf_pane.modeChanged(mode);
+	}
+    }
+
+    //   public void refresh (int refresh_reason, boolean collection_loaded)
+    public void refresh () {
+	if (log_pane != null ){
+	}
+    }
+
+    public void returnToInitialPane(){
+	if (log_pane != null) {
+	    tab_pane.setSelectedComponent(log_pane);
+	}
+    }
+    public void wait(boolean waiting) {
+	Component glass_pane = getGlassPane();
+	if(waiting) {
+	    // Show wait cursor.
+	    //glass_pane.addMouseListener(mouse_blocker_listener);
+	    glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+	    glass_pane.setVisible(true);
+	}
+	else {
+	    // Hide wait cursor.
+	    glass_pane.setVisible(false);
+	    glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+	    //glass_pane.removeMouseListener(mouse_blocker_listener);
+	}
+	glass_pane = null;
+    }
+
+    private class TabUpdater
+	implements Runnable {
+	private boolean ready = false;
+	private int conf_pos = -1;
+	private int ext_pos = -1;
+	private int monitor_pos = -1;
+	private int log_pos = -1;
+	private JTabbedPane tab_pane = null;
+	
+	public TabUpdater (JTabbedPane tab_pane, boolean ready){
+	    this.ready = ready;
+	    this.tab_pane = tab_pane;
+	    conf_pos = tab_pane.indexOfComponent(conf_pane);
+	    ext_pos = tab_pane.indexOfComponent(ext_pane);
+	    monitor_pos = tab_pane.indexOfComponent(monitor_pane);  
+	    log_pos = tab_pane.indexOfComponent(log_pane);
+	}
+	
+	public void run() {
+	    if (conf_pos != -1){
+		if (ready) {
+		    tab_pane.setEnabledAt (conf_pos,Configuration.get("admin.conf"));
+		} else {
+		    tab_pane.setEnabledAt (conf_pos,false);
+		}
+	    }
+	    if (ext_pos != -1){
+		if (ready) {
+		    tab_pane.setEnabledAt (ext_pos,Configuration.get("admin.ext"));
+		} else {
+		    tab_pane.setEnabledAt (ext_pos,false);
+		}
+	    }
+	    if (monitor_pos != -1){
+		if (ready) {
+		    tab_pane.setEnabledAt (monitor_pos,Configuration.get("admin.monitor"));
+		} else {
+		    tab_pane.setEnabledAt (monitor_pos,false);
+		}
+	    }
+	    if (log_pos != -1){
+		if (ready) {
+		    tab_pane.setEnabledAt (log_pos,Configuration.get("admin.log"));
+		} else {
+		    tab_pane.setEnabledAt (log_pos,false);
+		}
+	    }
+	}
+	public void setReady (boolean ready){
+
+	    this.ready = ready;
+	}
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/admin/config.xml
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/admin/config.xml	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/admin/config.xml	(revision 14125)
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE Configuration [
+  <!ELEMENT Configuration  (GathererConfig, Other, DirectoryMappings, Associations)>
+  <!ELEMENT GathererConfig (Argument*)>
+  <!ELEMENT Argument       (#PCDATA)>
+  <!ATTLIST Argument
+            name           CDATA #REQUIRED>
+  <!ELEMENT Other          (Info*)>
+  <!ELEMENT Info           (Name, Desc, Arguments)>
+  <!ELEMENT Arguments      (Option*)>
+  <!ELEMENT Option         (Name, Desc, Type, Required, Default?, List?)>
+  <!ELEMENT Type           (#PCDATA)>
+  <!ELEMENT Required       (#PCDATA)>
+  <!ELEMENT Default        (#PCDATA)>
+  <!ELEMENT List           (Value*)>
+  <!ELEMENT Value          (Name, Desc?)>
+  <!ELEMENT Name           (#PCDATA)>
+  <!ELEMENT Desc           (#PCDATA)>
+  <!ELEMENT DirectoryMappings (Mapping*)>
+  <!ELEMENT Mapping           (#PCDATA)>
+  <!ATTLIST Mapping 
+            name              CDATA #REQUIRED
+	    file              CDATA #REQUIRED>
+  <!ELEMENT Associations (Entry*)>
+  <!ELEMENT Entry (#PCDATA)>
+  <!ATTLIST Entry
+            extension CDATA #REQUIRED>
+]>
+
+<Configuration version="2.53a">
+  <GathererConfig>
+    <!-- ***** General Options: apply globally to the GAI execution. ***** -->
+    <!-- The location and size of the main Gatherer window. -->
+    <Argument name="general.bounds">0, 0, 800, 600</Argument>
+    <!-- Are we expected to produce a debug file. Can be overidden at start up. default = [false] -->
+    <Argument name="general.debug">false</Argument>
+    <!-- The standard font used in the Gatherer. [Verdana, BOLD, 12] -->
+    <Argument name="general.font">Verdana, BOLD, 12</Argument>
+    <Argument name="general.library_url"/>
+    <Argument name="general.locale">en_NZ</Argument>
+    <!-- How many folders deep should we recurse before suspecting a cyclic path? [40] -->
+    <Argument name="general.max_folder_depth">40</Argument>
+    <!-- The mode controls what level a detail is presented to the user - ranging from a basic, no regex, no perl experience up to complete details for all processes. The values, ranging from lowest to highest detail, are: 1 = Assistant, 2 = Librarian, 3 = Systems, 4 = Expert [default 2]-->
+    <Argument name="general.mode">2</Argument>
+    <Argument name="general.open_collection"></Argument>
+    <!-- The application launching command used when previewing the collection. [default -blank-] -->
+    <Argument name="general.preview_program"></Argument>
+    <Argument name="general.proxy_host"></Argument>
+    <Argument name="general.proxy_port"></Argument>
+    <Argument name="general.show_file_size">false</Argument>
+    <!-- Do we expect to connect to the internet via a proxy server. [false] -->
+    <Argument name="general.use_proxy">false</Argument>
+    <Argument name="general.view_extracted_metadata">true</Argument>
+
+    <!-- Colouring -->
+    <Argument name="coloring.button_background">218, 237, 252</Argument>
+    <Argument name="coloring.button_foreground">0, 0, 0</Argument>
+    <Argument name="coloring.button_selected_background">128, 180, 216</Argument>
+    <Argument name="coloring.button_selected_foreground">255, 255, 255</Argument>
+    <Argument name="coloring.collection_heading_background">176, 208, 176</Argument>  
+    <Argument name="coloring.collection_heading_foreground">0, 0, 0</Argument>
+    <Argument name="coloring.collection_selection_background">128, 180, 216</Argument>
+    <Argument name="coloring.collection_selection_foreground">0, 0, 0</Argument>
+    <Argument name="coloring.collection_tree_background">224, 240, 224</Argument>
+    <Argument name="coloring.collection_tree_foreground">0, 0, 0</Argument>
+    <Argument name="coloring.collection_noneditable_background">192, 192, 192</Argument>
+    <Argument name="coloring.collection_noneditable_foreground">0, 0, 0</Argument>
+    <Argument name="coloring.disabled">206, 206, 206</Argument>
+    <Argument name="coloring.editable_background">255, 255, 255</Argument>
+    <Argument name="coloring.editable_foreground">0, 0, 0</Argument>
+    <Argument name="coloring.error_background">255, 0, 0</Argument>
+    <Argument name="coloring.error_foreground">0, 0, 0</Argument>
+    <Argument name="coloring.scrollbar_background">192, 192, 192</Argument>
+    <Argument name="coloring.scrollbar_foreground">255, 255, 255</Argument>
+    <Argument name="coloring.workspace_heading_background">128, 180, 216</Argument>
+    <Argument name="coloring.workspace_heading_foreground">0, 0, 0</Argument>
+    <Argument name="coloring.workspace_selection_background">176, 208, 176</Argument>
+    <Argument name="coloring.workspace_selection_foreground">0, 0, 0</Argument>
+    <Argument name="coloring.workspace_tree_background">218, 237, 252</Argument>
+    <Argument name="coloring.workspace_tree_foreground">0, 0, 0</Argument>
+
+    <!-- Mirroring -->
+    <!-- Mirroring has many particular options. These show the default settings. -->
+   <!-- <Argument name="mirroring.depth">0</Argument>
+    <Argument name="mirroring.no_parents">true</Argument>
+    <Argument name="mirroring.other_hosts">false</Argument>
+    <Argument name="mirroring.overwrite">false</Argument>
+    <Argument name="mirroring.page_requisites">true</Argument>
+    <Argument name="mirroring.quiet">true</Argument>
+    <Argument name="mirroring.remove_failed">false</Argument>-->
+
+    <!-- Warnings -->
+    <!-- Warnings can be disabled by the user. -->
+    <Argument name="warning.CollectionBuilt">true</Argument>
+    <Argument name="warning.DirectoryLevelMetadata">true</Argument>
+    <Argument name="warning.ExtractedMetadata">true</Argument>
+    <Argument name="warning.InheritedMetadata">true</Argument>
+    <Argument name="warning.MissingEXEC">true</Argument>
+    <Argument name="warning.MissingGSDL">true</Argument>
+    <Argument name="warning.MissingPERL">true</Argument>
+    <Argument name="warning.MissingWGET">true</Argument>
+    <Argument name="warning.NoMetadataSetsSelected">true</Argument>
+    <Argument name="warning.NoPluginExpectedToProcessFile">true</Argument>
+    <Argument name="warning.OldWGET">true</Argument>
+    <Argument name="warning.TitleClashes">true</Argument>
+
+    <!-- Workflow -->
+    <!-- Disabling a view here will cause it to be hidden from the Gatherer display. -->
+    <Argument name="admin.conf">true</Argument>
+    <Argument name="admin.ext">true</Argument> 
+    <Argument name="admin.monitor">true</Argument>
+    <Argument name="admin.log">true</Argument> 
+
+    <Argument name="GEMS.Preferences.Selected_Languages">en</Argument>
+  </GathererConfig>
+
+  <Other/>
+  <DirectoryMappings/>
+  <Associations>
+    <Entry extension="doc"/>
+    <Entry extension="gif"/>
+    <Entry extension="htm"/>
+    <Entry extension="html"/>
+    <Entry extension="jpg"/>
+    <Entry extension="jpeg"/>
+    <Entry extension="pdf"/>
+    <Entry extension="png"/>
+    <Entry extension="ps"/>
+    <Entry extension="rtf"/>
+    <Entry extension="txt"/>
+    <Entry extension="text"/>
+  </Associations>
+</Configuration>
Index: /greenstone3/trunk/src/java/org/greenstone/admin/gui/ClearLogFilePrompt.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/admin/gui/ClearLogFilePrompt.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/admin/gui/ClearLogFilePrompt.java	(revision 14125)
@@ -0,0 +1,124 @@
+/**
+ *#########################################################################
+ *
+ * A component of the GAI application, part of the Greenstone digital
+ * library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * <BR><BR>
+ *
+ * Author: John Thompson, Greenstone Digital Library, University of Waikato
+ * Modified by: Chi-Yu Huang
+ *
+ * <BR><BR>
+ *
+ * Copyright (C) 1999 New Zealand Digital Library Project
+ *
+ * <BR><BR>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * <BR><BR>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * <BR><BR>
+ *
+ * You should have received a copy of the 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 org.greenstone.admin.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.net.*;
+import javax.swing.*;
+import javax.swing.event.*;
+
+/*import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.LocalLibraryServer;
+import org.greenstone.gatherer.collection.BasicCollectionConfiguration;
+import org.greenstone.gatherer.file.WorkspaceTree;  // !!! Don't like this here
+import org.greenstone.gatherer.util.ArrayTools;
+import org.greenstone.gatherer.util.StaticStrings;*/
+
+
+/** This class provides the functionality to delete current collections from the 
+ ** GSDLHOME/collect/ directory. The user chooses the collection from a list, where 
+ ** each entry also displays details about itself, confirms the delete of a collection 
+ ** by checking a checkbox then presses the ok button to actually delete the collection.
+ * @author Chi-Yu Huang, Greenstone Digital Library, University of Waikato
+ * @version 1.0
+ */
+public class ClearLogFilePrompt 
+	extends JDialog {
+    
+    /** A reference to ourself so any inner-classes can dispose of us. */
+    private ClearLogFilePrompt prompt = null;
+    private File log_file = null;
+
+    //A flag showing the deleting status
+    private boolean current_logfile_cleared = false;
+
+    /** The size of the delete prompt screen. */
+    static final Dimension SIZE = new Dimension(500, 500);
+
+    // Constructor.
+    public ClearLogFilePrompt() {
+	super();
+	prompt = this;
+    }
+    
+    /** Destructor. */
+    public void destroy() {
+	prompt = null;
+    }
+
+    /** This method causes the Clear Confirmation Dialog to be displayed. 
+     * returns true if it has deleted the log file that is currently open */
+    public boolean display(File log_file) {
+	int result = JOptionPane.showConfirmDialog((Component) null, "Do you really want to clear this log file", "Clear Confirmation", JOptionPane.YES_NO_OPTION);
+	if ( result == JOptionPane.YES_OPTION) {
+	    log_file.delete();
+	    try {
+		log_file.createNewFile();
+	    } catch (Exception e) {
+		e.printStackTrace();
+	    }	     
+	    current_logfile_cleared = true;
+	} else if (result == JOptionPane.NO_OPTION) {
+	    current_logfile_cleared = false;
+	    JOptionPane.showMessageDialog(prompt, "Cancel clearing the " + log_file.getPath() +" log file");
+	    prompt.dispose();
+	}
+	return current_logfile_cleared;
+    }
+    
+    
+    /** Shows a delete complete prompt. 
+     * @param success A <strong>boolean</strong> indicating if the collection was successfully deleted.
+     * @see org.greenstone.gatherer.collection.Collection
+     */
+    /*public void resultPrompt(boolean success) {
+	if (success) {
+	    JOptionPane.showMessageDialog(prompt,"Selected log file has been deleted. You have to restart the action to create the log file");
+	} else {
+	    JOptionPane.showMessageDialog(prompt, "Cancel deleting the log file");
+	}
+	}*/
+    
+    /** Any implementation of ActionListener requires this method so that when an 
+     **action is performed the appropriate effect can occur.*/
+    public void actionPerformed(ActionEvent event) {
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/admin/gui/ConfPane.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/admin/gui/ConfPane.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/admin/gui/ConfPane.java	(revision 14125)
@@ -0,0 +1,940 @@
+/**
+ *#########################################################################
+ *
+ * A component of the GAI application, part of the Greenstone digital
+ * library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * <BR><BR>
+ *
+ * Author: Chi-Yu Huang, Greenstone Digital Library, University of Waikato
+ * Modified: 03.2005
+ *
+ * <BR><BR>
+ *
+ * Copyright (C) 1999 New Zealand Digital Library Project
+ *
+ * <BR><BR>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * <BR><BR>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * <BR><BR>
+ *
+ * You should have received a copy of the 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 org.greenstone.admin.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import java.lang.Object;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.tree.*;
+import javax.swing.table.*;
+import java.awt.event.MouseEvent;
+import java.net.*;
+import java.sql.*;
+
+import org.greenstone.admin.GAI;
+import org.greenstone.admin.GAIManager;
+import org.greenstone.admin.Configuration;
+import org.greenstone.admin.gui.ThreadControl;
+//import org.greenstone.admin.gui.ConfSettingTableModel;
+import org.greenstone.admin.gui.SiteConfSetting;
+import org.greenstone.core.ParsingProgress;
+import org.greenstone.gsdl3.util.GSFile;
+
+/** The Configuration pane is to view the status of relevant configure files in GSIII
+ * @author Chi-Yu Huang, Greenstone Digital Library, University of Waikato
+ * @version
+ */
+public class ConfPane
+    extends JPanel
+    implements ActionListener {
+
+    /* The pane to demonstrate Configuration information, including the build property file
+     * being monitored and their content, and control functions */
+    protected JSplitPane main_conf_pane = null;
+    
+    protected JPanel main_contentPane = null;
+    public Hashtable conf_table;
+    
+    /** The panel that contains a Conf_list */
+    private JPanel confList_pane =  null;
+    
+    /** The panel that contains the conf content. */
+    private JPanel confContent_pane =  null;
+    private JScrollPane conf_table_pane = null;
+    
+    /** The List showing all the Configuration files concerned. */
+    private JList conf_list=null;
+    private JTree conf_tree = null;
+
+    /** The label at the top of the confList_pane. */
+    private JLabel confList_label =  null;
+    /** The label shown at the top of the confContent Pane. */
+    private JLabel confContent_label  =  null;
+
+    // The control buttons used to manipulate Configuration Pane
+    protected JPanel inner_button_pane = null;
+    protected JPanel inner_control_pane = null;
+    protected JPanel tomcat_button_pane = null;
+    protected JPanel mysql_button_pane = null;
+    protected JPanel setting_shown_pane = null;
+    
+    /**Buttons in inner button pane */
+    private JButton startup_tomcat_button = null;
+    private JButton shutdown_tomcat_button = null;
+    private JButton restart_tomcat_button = null;
+    private JButton startup_mysql_button = null;
+    private JButton shutdown_mysql_button = null;
+    private JButton restart_mysql_button = null;
+
+    private JButton save_button = null;
+
+    private JLabel conf_label = null;
+    private JLabel conf_setting_label = null;
+    
+    /* ConfPane empty AREA to show XML configuration file*/
+    //private JTextArea conf_xml_area = null;
+
+    //control tomcat and mysql server running status
+    private String tomcat_server;
+    private String tomcat_port;
+    private String mysql_adminuser;
+    private String mysql_server;
+    private String mysql_port;
+    private String conf_pane_name;
+  
+    private boolean tomcat_server_up = false;
+    private boolean mysql_server_up = false;
+
+    /** The scrollable area into which the configuration content is placed. */
+    //private JScrollPane conf_xml_content = null;
+    
+    public SiteConfSetting site_conf = null;
+    public SiteConfSetting interface_conf = null;
+
+    /** The various sizes for the screen layout*/
+    static private Dimension MIN_SIZE = new Dimension( 90,  90);
+    static private Dimension LIST_SIZE  = new Dimension(200, 450);
+    static private Dimension CONTENT_SIZE = new Dimension (600,450);
+    static private Dimension TABLE_SIZE = new Dimension(500,200);
+    static private int MINIMUM_TABLE_HEADER_SIZE = 15;
+    
+    private JTable conf_setting_table = null;
+
+    private int num_of_setting;
+
+    //The details display in the table
+    int display_row_count = 5;
+    int rowLength = 20;
+    int colLength = 3;
+    private Object[][] conf_display = new Object [rowLength][colLength];
+    private Object[][] conf_setting;
+    
+    //An array to store all the details in the build.properties file
+    private ArrayList conf_array;
+    
+    //Site configuration
+    // TODO!! there are more than one site and interface - need to extend this
+    public File site_conf_file = new File(GSFile.siteConfigFile(GSFile.siteHome(GAI.gsdl3_web_home, "localsite")));
+    public File interface_conf_file = new File(GSFile.interfaceConfigFile(GSFile.interfaceHome(GAI.gsdl3_web_home, "default")));
+    public boolean  project_conf_changed = false;
+
+    ConfSettingTableModel conf_table_model = null;
+    DefaultMutableTreeNode top = new DefaultMutableTreeNode("Configuration Files");
+    //Constructor
+    public ConfPane() {
+	conf_table = new Hashtable();
+	// create all the control button panes
+	inner_control_pane = new JPanel();
+	inner_button_pane = new JPanel();
+	tomcat_button_pane = new JPanel();
+	mysql_button_pane = new JPanel();
+	
+	/*the class for showing the site configurations including
+	 * siteConfig.xml and interfaceConfig.xml
+	 */
+	site_conf = new SiteConfSetting("siteConfig", site_conf_file);
+	interface_conf =  new SiteConfSetting("interfaceConfig", interface_conf_file);
+	
+	// Main Configuration Pane
+	main_conf_pane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
+       	// Main pane for Configuration Content Pane
+	main_contentPane = new JPanel();
+	
+	//Create a tree for a list Configuration files we are interested
+	//DefaultMutableTreeNode child1 = new DefaultMutableTreeNode();
+	DefaultMutableTreeNode child1 = new DefaultMutableTreeNode("Project Configuration");
+
+	DefaultMutableTreeNode compile = new DefaultMutableTreeNode("Compile");
+	DefaultMutableTreeNode tomcat = new DefaultMutableTreeNode("Tomcat");
+	DefaultMutableTreeNode proxy = new DefaultMutableTreeNode("Proxy");
+	DefaultMutableTreeNode mysql = new DefaultMutableTreeNode("MySQL");	
+	DefaultMutableTreeNode gsdl = new DefaultMutableTreeNode("GSDL");
+	child1.add(compile);
+	child1.add(tomcat);
+	child1.add(proxy);
+	child1.add(mysql);
+	child1.add(gsdl);
+
+	DefaultMutableTreeNode child2 = new DefaultMutableTreeNode("Site Configuration");
+	//DefaultMutableTreeNode child2 = new DefaultMutableTreeNode();	
+	DefaultMutableTreeNode siteConf = new DefaultMutableTreeNode("SiteConfig");
+	DefaultMutableTreeNode interfaceConf = new DefaultMutableTreeNode("InterfaceConfig");
+	child2.add(siteConf);
+	child2.add(interfaceConf);
+
+	//DefaultMutableTreeNode child3 = new DefaultMutableTreeNode("Conf 3");
+	top.add(child1);
+	top.add(child2);
+	//top.add(child3);
+	conf_tree = new JTree(top);
+	conf_tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+	conf_tree.addTreeSelectionListener(new ConfTreeListener());
+
+	// inner button_pane Buttons
+	StartupTomcatButtonListener stbl = new StartupTomcatButtonListener();
+	ShutdownTomcatButtonListener stdbl = new ShutdownTomcatButtonListener();
+	RestartTomcatButtonListener rtbl = new RestartTomcatButtonListener();
+
+	StartupMysqlButtonListener smbl = new StartupMysqlButtonListener();
+	ShutdownMysqlButtonListener smdbl = new ShutdownMysqlButtonListener();
+	RestartMysqlButtonListener rmbl = new RestartMysqlButtonListener();
+		
+	ImageIcon startupTomcatButtonIcon = new ImageIcon(GAI.images_path + "redo.gif");
+	ImageIcon shutdownTomcatButtonIcon = new ImageIcon(GAI.images_path + "stop.gif");
+	ImageIcon restartTomcatButtonIcon = new ImageIcon(GAI.images_path + "stop.gif");
+	
+	ImageIcon startupMysqlButtonIcon = new ImageIcon(GAI.images_path + "redo.gif");
+	ImageIcon shutdownMysqlButtonIcon = new ImageIcon(GAI.images_path + "stop.gif");
+	ImageIcon restartMysqlButtonIcon = new ImageIcon(GAI.images_path + "stop.gif");
+	ImageIcon saveButtonIcon = new ImageIcon(GAI.images_path  + "save.gif");
+
+	startup_tomcat_button = new JButton();	
+	startup_tomcat_button.addActionListener(stbl);
+	startup_tomcat_button.setMnemonic(KeyEvent.VK_S);
+	startup_tomcat_button.setEnabled(false);
+	startup_tomcat_button.setText(GAI.dictionary.get("ConfPane.Tomcat_Startup"));
+	startup_tomcat_button.setToolTipText(GAI.dictionary.get("ConfPane.Tomcat_Startup_Tooltip"));
+
+	shutdown_tomcat_button = new JButton();
+	shutdown_tomcat_button.addActionListener(stdbl);
+	shutdown_tomcat_button.setEnabled(false);
+	shutdown_tomcat_button.setText(GAI.dictionary.get("ConfPane.Tomcat_Shutdown"));
+	shutdown_tomcat_button.setToolTipText(GAI.dictionary.get("ConfPane.Tomcat_Shutdown_Tooltip"));
+
+	restart_tomcat_button = new JButton();
+	restart_tomcat_button.addActionListener(rtbl);
+	restart_tomcat_button.setEnabled(false);
+	restart_tomcat_button.setText(GAI.dictionary.get("ConfPane.Tomcat_Restart"));
+	restart_tomcat_button.setToolTipText(GAI.dictionary.get("ConfPane.Tomcat_Restart_Tooltip"));
+
+	startup_mysql_button = new JButton();
+	startup_mysql_button.addActionListener(smbl);
+	startup_mysql_button.setMnemonic(KeyEvent.VK_S);
+	startup_mysql_button.setEnabled(false);
+	startup_mysql_button.setText(GAI.dictionary.get("ConfPane.MySQL_Startup"));
+	startup_mysql_button.setToolTipText(GAI.dictionary.get("ConfPane.MySQL_Startup_Tooltip"));
+
+	shutdown_mysql_button = new JButton();
+	shutdown_mysql_button.addActionListener(smdbl);
+	shutdown_mysql_button.setEnabled(false);
+	shutdown_mysql_button.setText(GAI.dictionary.get("ConfPane.MySQL_Shutdown"));
+	shutdown_mysql_button.setToolTipText(GAI.dictionary.get("ConfPane.MySQL_Shutdown_Tooltip"));
+	
+	restart_mysql_button = new JButton();
+	restart_mysql_button.addActionListener(rmbl);
+	restart_mysql_button.setEnabled(false);
+	restart_mysql_button.setText(GAI.dictionary.get("ConfPane.MySQL_Restart"));
+	restart_mysql_button.setToolTipText(GAI.dictionary.get("ConfPane.MySQL_Restart_Tooltip"));
+
+	//tomcat control buttons
+	stbl = null;
+	stdbl = null;
+	rtbl = null;
+	
+	//mysql control button
+	smbl = null;
+	smdbl = null;
+	rmbl = null;
+	
+	//read in build properties
+	getConfContent();
+    }
+
+    /** Any implementation of ActionListener requires this method so that when an 
+     **action is performed the appropriate effect can occur.*/
+    public void actionPerformed(ActionEvent event) {
+    }
+    
+    
+    /** This method is called to actually layout the components.*/
+    public void display() {
+	//Create Components.
+	//KeyListenerImpl key_listener = new KeyListenerImpl();
+	//MouseListenerImpl mouse_listener = new MouseListenerImpl();
+	//this.addKeyListener(key_listener);
+	
+	//confList_Pane
+	confList_pane = new JPanel();
+	confList_pane.setBorder(BorderFactory.createLoweredBevelBorder());
+	confList_pane.setPreferredSize(LIST_SIZE);
+	confList_pane.setSize(LIST_SIZE);
+	confList_pane.setBackground(Configuration.getColor("coloring.workspace_selection_background"));
+	confList_pane.setForeground(Configuration.getColor("coloring.workspace_selection_foreground"));
+	
+	confList_label = new JLabel();
+	confList_label.setOpaque(true);
+	confList_label.setBackground(Configuration.getColor("coloring.workspace_selection_background"));
+	confList_label.setForeground(Configuration.getColor("coloring.workspace_selection_foreground"));
+	confList_label.setText(GAI.dictionary.get("ConfPane.Conf_List"));
+
+	// confContent_Pane
+	confContent_pane = new JPanel();
+	confContent_pane.setBorder(BorderFactory.createEmptyBorder(10,20,10,20));
+	confContent_pane.setBackground(Configuration.getColor("coloring.workspace_selection_background"));
+	confContent_pane.setForeground(Configuration.getColor("coloring.workspace_selection_foreground"));
+
+	confContent_label = new JLabel();
+	confContent_label.setOpaque(true);
+	confContent_label.setBackground(Configuration.getColor("coloring.workspace_selection_background"));
+	confContent_label.setForeground(Configuration.getColor("coloring.workspace_selection_foreground"));
+	confContent_label.setText(GAI.dictionary.get("ConfPane.Conf_Content"));
+		
+	conf_table_model = new ConfSettingTableModel();
+	conf_setting_table = new JTable(conf_table_model){
+		public String getToolTipText(MouseEvent e){
+		    String tip = null;
+		    Point p = e.getPoint();
+		    int rowIndex = rowAtPoint(p);
+		    int colIndex = columnAtPoint(p);
+		    int realColumnIndex = convertColumnIndexToModel(colIndex);
+		    if (realColumnIndex == 0){
+			tip = conf_display[rowIndex][realColumnIndex].toString();
+		    } else {
+			tip = super.getToolTipText(e);
+		    }
+		    return tip;
+		}
+		public Component prepareRenderer (TableCellRenderer renderer, 
+						  int rowIndex, int colIndex){
+		    Component c = super.prepareRenderer(renderer, rowIndex, colIndex);
+		    if (colIndex == 0) {
+			c.setBackground(Configuration.getColor("coloring.table_noneditable_background"));
+		    } else {
+			c.setBackground(Configuration.getColor("coloring.table_editable_background"));
+		    }
+		    return c;
+		}
+	    };
+	
+	//When the MySQL and TOMCAT servers are still running and detect double-clicking occuring (editing mode)
+	conf_setting_table.addMouseListener(new MouseAdapter(){
+		public void mouseClicked(MouseEvent e){
+		    if (e.getClickCount() == 2){ 
+			if (conf_pane_name.matches("MYSQL")){
+			    mysql_server_up = false;
+			    mysql_server_up = checkMysqlServer();
+			    if (mysql_server_up) {
+				JOptionPane.showMessageDialog((Component) null,"MySQL is running, shutdown the MySQL server before making any changes");
+			    }
+			}
+			if (conf_pane_name.matches("TOMCAT")){
+			    tomcat_server_up = false;
+			    tomcat_server_up = checkTomcatServer();
+			    if (tomcat_server_up) {
+				JOptionPane.showMessageDialog((Component) null,"TOMCAT is running, shutdown the TOMCAT server before making any changes");
+			    }
+			}	
+		    }
+		}
+	    });
+	conf_setting_table.addKeyListener(new KeyAdapter(){
+		public void keyPressed(KeyEvent ke){
+		    if (ke.getKeyCode() == KeyEvent.VK_F2){ 
+			if (conf_pane_name.matches("MYSQL")){
+			    mysql_server_up = checkMysqlServer();
+			    if (mysql_server_up) {
+				JOptionPane.showMessageDialog((Component) null,"MySQL is running, shutdown the MySQL server before making any changes");
+			    }
+			}
+			if (conf_pane_name.matches("TOMCAT")){
+			    tomcat_server_up = checkTomcatServer();
+			    if (tomcat_server_up) {
+				JOptionPane.showMessageDialog((Component) null,"TOMCAT is running, shutdown the TOMCAT server before making any changes");
+			    }
+			}
+		    }
+		}
+	    });
+	
+	//Set up tableHeader
+	JTableHeader table_header = conf_setting_table.getTableHeader();
+	Dimension table_header_preferred_size = table_header.getPreferredSize();
+	if (table_header_preferred_size.height < MINIMUM_TABLE_HEADER_SIZE) {
+	    table_header_preferred_size.setSize(table_header_preferred_size.width, MINIMUM_TABLE_HEADER_SIZE);
+	    table_header.setPreferredSize(table_header_preferred_size);
+	}
+
+	table_header.setFont(new Font("Arial", Font.BOLD, 13));
+	conf_setting_table.setRowHeight(30);
+	conf_table_pane = new JScrollPane(conf_setting_table);
+	conf_table_pane.setVisible(false);
+	conf_table_pane.getViewport().setBackground(Configuration.getColor("coloring.collection_tree_background"));
+	
+	// Layout Components
+	confList_pane.setLayout(new BorderLayout());
+	JScrollPane conf_treeView = new JScrollPane(conf_tree);
+	confList_pane.add(conf_treeView, BorderLayout.CENTER);
+	confList_pane.add(confList_label, BorderLayout.NORTH);
+	confContent_pane.setLayout(new BorderLayout());
+	confContent_pane.add(conf_table_pane, BorderLayout.CENTER);
+	
+	inner_button_pane.setLayout(new GridLayout(1,2));
+	inner_control_pane.setLayout (new BorderLayout());
+	inner_control_pane.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));
+	inner_control_pane.setPreferredSize(new Dimension(50,50));
+	inner_control_pane.setSize(new Dimension(50,50));
+	inner_control_pane.add (inner_button_pane, BorderLayout.CENTER);
+	
+	main_contentPane.setLayout (new BorderLayout());
+	main_contentPane.add(confContent_label, BorderLayout.NORTH);
+	main_contentPane.add(confContent_pane, BorderLayout.CENTER);
+	main_contentPane.add(inner_control_pane, BorderLayout.SOUTH);
+	main_conf_pane.add(confList_pane, JSplitPane.LEFT);
+	main_conf_pane.add(main_contentPane, JSplitPane.RIGHT);
+	main_conf_pane.setDividerLocation(LIST_SIZE.width - 10);
+	
+	this.setLayout(new BorderLayout());
+	this.add(main_conf_pane, BorderLayout.CENTER);
+    }
+
+    public void save() {
+	if (project_conf_changed) {
+	    saveProjectConf(GAI.build_properties_file);
+	}
+	if (site_conf.confChanged()){
+	    site_conf.saveFile(site_conf_file);
+	}
+	if (interface_conf.confChanged()) {
+	    interface_conf.saveFile(interface_conf_file);
+	}
+	
+
+    }
+    
+    public boolean configurationChanged() {
+	return (project_conf_changed || site_conf.confChanged() ||
+		interface_conf.confChanged());
+
+    }
+
+    private class StartupTomcatButtonListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    /*before startup Tomcat server, we want to make sure project and Site configuration 
+	     * files are saved*/
+	    if (project_conf_changed) {
+		saveProjectConf(GAI.build_properties_file);
+	    }
+	    /*boolean site_conf_changed = site_conf.confChanged();
+	    boolean interface_conf_changed=interface_conf.confChanged();
+	    if (site_conf_changed) {
+		site_conf.saveFile(site_conf_file);
+	    }
+	    if (interface_conf_changed) {
+		interface_conf.saveFile(interface_conf_file);
+		}*/
+	    tomcat_server_up = checkTomcatServer();
+	    if (!tomcat_server_up) {
+		ThreadControl threadControl = new ThreadControl();
+		Runnable startupTomcatThread = threadControl.new startupTomcatServer("start-tomcat");
+		new Thread(startupTomcatThread).start();
+		threadControl.destroy();
+		tomcat_server_up = true;
+		JOptionPane.showMessageDialog((Component) null,"Tomcat server has been Startup successfully!");  
+	    } else {
+		JOptionPane.showMessageDialog((Component) null,"Tomcat server is running");
+	    }
+	    changeTomcatButtonPane1();
+	}
+    }
+    
+    private class ShutdownTomcatButtonListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    tomcat_server_up = checkTomcatServer();
+	    if (tomcat_server_up){
+		ThreadControl threadControl = new ThreadControl();
+		Runnable shutdownTomcatThread = threadControl.new shutdownTomcatServer("stop-tomcat");
+		new Thread(shutdownTomcatThread).start();
+		threadControl.destroy();
+		tomcat_server_up = false;
+		JOptionPane.showMessageDialog((Component) null, "Tomcat server has been shutted down !");
+	    } else {
+		JOptionPane.showMessageDialog((Component) null,"Tomcat server was not running!");
+	    }
+	    changeTomcatButtonPane2();
+	}
+    }
+    
+    private class RestartTomcatButtonListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    //before we restart Tomcat server, we want to make sure the conf_pane settings are saved
+	    if (project_conf_changed) {
+		saveProjectConf(GAI.build_properties_file);
+	    }
+	    /*boolean site_conf_changed = site_conf.confChanged();
+	    boolean interface_conf_changed=interface_conf.confChanged();
+	    if (site_conf_changed) {
+		site_conf.saveFile(site_conf_file);
+	    }
+	    if (interface_conf_changed) {
+		interface_conf.saveFile(interface_conf_file);
+		}*/
+	    tomcat_server_up = checkTomcatServer();
+	    if (tomcat_server_up) {
+		ThreadControl threadControl = new ThreadControl();
+		Runnable restartTomcatThread = threadControl.new restartTomcatServer("restart-tomcat");
+ 		new Thread(restartTomcatThread).start();
+		threadControl.destroy();
+		tomcat_server_up = true;
+		JOptionPane.showMessageDialog((Component) null,"Tomcat server has been Restarted successfully!"); 
+	    } else {
+		JOptionPane.showMessageDialog((Component) null,"Tomcat server was not running!"); 
+	    }
+	}
+    }
+    
+    private class StartupMysqlButtonListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    //before we startup the MySQL server, we want to make sure the Conf_pane settings are saved
+	    saveProjectConf(GAI.build_properties_file);
+	    mysql_server_up = checkMysqlServer();
+	    if (!mysql_server_up) {
+		ThreadControl threadControl = new ThreadControl();
+		Runnable startupMysqlThread = threadControl.new startupMysqlServer("start-mysql");
+		new Thread(startupMysqlThread).start();
+		threadControl.destroy();
+		mysql_server_up = true;
+		JOptionPane.showMessageDialog((Component) null,"MYSQL server has been Startup successfully!");  
+	    } else {
+		JOptionPane.showMessageDialog((Component) null,"MYSQL server has been running");  	
+	    }
+	    changeMysqlButtonPane1();
+	}
+    }  
+    
+    private class ShutdownMysqlButtonListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    mysql_server_up = checkMysqlServer();
+	    if (mysql_server_up){
+		ThreadControl threadControl = new ThreadControl();
+		Runnable shutdownMysqlThread = threadControl.new shutdownMysqlServer("stop-mysql");
+		new Thread(shutdownMysqlThread).start();
+		threadControl.destroy();
+		JOptionPane.showMessageDialog((Component) null,"MYSQL server has been Shutdown successfully !");
+		mysql_server_up = false;
+	    } else {
+		JOptionPane.showMessageDialog((Component) null,"MYSQL server was not running!");
+	    }
+	    changeMysqlButtonPane2();
+	}
+    }
+    
+    private class RestartMysqlButtonListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    saveProjectConf(GAI.build_properties_file);
+	    mysql_server_up = checkMysqlServer();
+	    if (mysql_server_up) {
+		ThreadControl threadControl = new ThreadControl();
+		Runnable restartMysqlThread = threadControl.new restartMysqlServer("restart-mysql");
+		new Thread(restartMysqlThread).start();
+		threadControl.destroy();
+		JOptionPane.showMessageDialog((Component) null,"MYSQL server has been Restarted successfully!");  
+		mysql_server_up = true;
+	    } else { 
+		JOptionPane.showMessageDialog((Component) null,"MYSQL server was not running!"); 
+	    }
+	}
+    }
+
+    // Save the configuration file globally,when click File->Save or restart (or startup) Tomcat and MySQl server
+    public void saveProjectConf(File file){
+    	String new_string;
+	Enumeration keys = conf_table.keys();
+	String key;
+	String value;
+	String filename = file.getPath();
+	while (keys.hasMoreElements()) {
+	    key = (String) keys.nextElement();
+	    value = (String) conf_table.get(key);
+	    for (int j=0 ; j < conf_array.size(); j++){
+		if (((String)conf_array.get(j)).startsWith(key.toLowerCase())){
+		    new_string = key+"="+value; 
+		    conf_array.set(j, new_string.toLowerCase());
+		}
+	    }
+	}
+
+	try {
+	    BufferedWriter conf_out = new BufferedWriter(new FileWriter(filename));
+	    for (int j=0 ; j < conf_array.size(); j++){
+		conf_out.write(conf_array.get(j).toString());
+		conf_out.newLine();
+	    }
+	    conf_out.close();
+	    getConfContent();
+	    project_conf_changed = false;
+	} catch (Exception e) {
+	    e.printStackTrace();
+	}
+    }
+
+    public boolean projectConfChanged() {
+	return project_conf_changed;
+    }
+
+    public void getConfContent(){
+	String filename = GAI.build_properties_file.getPath();
+	if (!GAI.build_properties_file.exists()){ 
+	    JOptionPane.showMessageDialog((Component) null,"Build property file does not exist");  
+	} else {
+	    readProjectConf(filename);
+	}
+    }
+    
+    /* Read build.properties file 
+     * @param
+     */
+    public void readProjectConf (String filename) {
+	String fileLine;
+	/*inside the array will store, the conf_setting[i][0]:Comment, 
+	 * conf_setting[i][1]:Para and conf_setting[i][2]:Value
+	 * conf_array[] store all the details from the build.properties*/
+	conf_array = new ArrayList();
+	conf_setting = new Object [rowLength][colLength];
+	try {
+	    BufferedReader conf_in = new BufferedReader(new FileReader(filename));
+	    int i = 0;
+	    while ((fileLine = conf_in.readLine()) != null) {
+		// This is an empty line
+		if (fileLine.matches("^\\s*$")) {
+		    // Do Nothing
+		} else if (fileLine.matches("##.+")){
+		    //This line shows the specific service for these conf setting
+		    conf_array.add(fileLine);
+		} else 	if (fileLine.matches("#.+")){
+		    //This line is Configuration Comment line
+		    conf_array.add(fileLine);
+		    conf_setting[i][0] = fileLine.substring(1); // use 1 to get rid of the # symbol.
+		} else if (!fileLine.matches("#.+") && !fileLine.matches("^\\s*$") ){
+		    //This line is Setting line
+		    int end_index = fileLine.indexOf("=");
+		    conf_setting[i][1] = fileLine.substring(0,end_index).toUpperCase();
+		    conf_setting[i][2] = fileLine.substring(end_index+1);
+		    conf_table.put(conf_setting[i][1], conf_setting[i][2]);
+		    i++; //calculat the number of settings
+		    conf_array.add(fileLine);
+		} else {
+		    // Wrong character in the line
+		}
+	    }
+	    num_of_setting = i;
+	    for (int j=0; j<num_of_setting; j++){
+		if (conf_setting[j][1].toString().matches("TOMCAT.SERVER")){
+		    tomcat_server = conf_setting[j][2].toString();
+		}
+		if (conf_setting[j][1].toString().matches("TOMCAT.PORT")){
+		    tomcat_port = conf_setting[j][2].toString();
+		}
+		if (conf_setting[j][1].toString().matches("MYSQL.ADMIN.USER")){
+		    mysql_adminuser = conf_setting[j][2].toString();
+		}
+		if (conf_setting[j][1].toString().matches("MYSQL.SERVER")){
+		    mysql_server = conf_setting[j][2].toString();
+		}
+		if (conf_setting[j][1].toString().matches("MYSQL.PORT")){
+		    mysql_port = conf_setting[j][2].toString();
+		}	
+	    }
+	    conf_in.close();
+	} catch (Exception e) {
+	    e.printStackTrace();
+	}
+    }
+    
+
+    public void clearTable (){
+	for (int i=0; i< rowLength; i++){
+	    conf_display[i][0] = "";
+	    conf_display[i][1] = "";
+	    conf_display[i][2] = "";
+	}
+    }
+
+    private boolean checkTomcatServer (){
+	try {
+	    if (tomcat_server != "" && tomcat_port != ""){
+		String http_string = "http://" + tomcat_server+":"+tomcat_port+"/";
+		URL tomcatURL = new URL(http_string);
+		HttpURLConnection tomcatConn = (HttpURLConnection) tomcatURL.openConnection();
+		tomcatConn.connect();
+		//necessary to get a Response, even if you don't care about contents
+		InputStream connIn = tomcatConn.getInputStream(); 
+		int pageStatus = tomcatConn.getResponseCode();
+		if (pageStatus == HttpURLConnection.HTTP_NOT_FOUND) {//404 error
+		    //Tomcat is not running
+		    tomcat_server_up = false;
+		} else {
+		    tomcat_server_up = true;
+		}  
+	    } else {
+		System.err.println("Either Tomcat server or Tomcat port was not set properly");
+	    }
+	} catch (Exception ex) {
+	    tomcat_server_up = false;
+	    System.err.println(ex.getMessage());
+	}
+	return tomcat_server_up;
+    }
+    
+    private boolean checkMysqlServer(){
+	Connection conn = null;
+	try {
+	    String mysql_userName ="gsdl3reader";
+	    String mysql_password = ""; 
+	    String mysql_url ="jdbc:mysql://"+mysql_server+":"+mysql_port+"/localsite_gs3mgdemo";
+	    //System.err.println("what is Mysql_URL:" + mysql_url);
+	    Class.forName("com.mysql.jdbc.Driver").newInstance();
+	    conn = DriverManager.getConnection(mysql_url, mysql_userName, mysql_password);
+	    if (conn == null) {
+		mysql_server_up =false;
+	    } else {
+		mysql_server_up = true;
+	    }
+	} catch (Exception e) {
+	    mysql_server_up = false;
+	    System.err.println("Cannot connect to database server");
+	}
+	return mysql_server_up;
+    }
+    
+    public class ConfSettingTableModel 
+	extends AbstractTableModel
+	{
+	String[] columnNames = {"Configuration Parameter",
+	"Configuration Value"};
+	
+	public int getColumnCount(){
+	return columnNames.length;
+	}
+	
+	public int getRowCount() {
+	return display_row_count;
+	}
+	
+	public String getColumnName(int col){
+	    
+	    return columnNames[col];
+	}
+	
+	public Object getValueAt(int row,int col){
+	    return conf_display[row][col+1];
+	}
+	
+	public boolean isCellEditable(int row, int col){
+	    if (col==0){
+		return false;
+	    } else if (conf_display[row][col].toString().matches("MYSQL.+")){
+		mysql_server_up = checkMysqlServer();
+		if (mysql_server_up) {
+		    return false;
+		}
+	    } else if (conf_display[row][col].toString().matches("TOMCAT.+")){
+	   	tomcat_server_up = checkTomcatServer();
+		if (tomcat_server_up) {
+		   return false;
+		}
+	    }
+	    return true;
+	}
+	
+	public void setValueAt(Object value, int row, int col){
+	    if (!isCellEditable(row, col))
+		return;
+	    conf_display[row][col+1] = value;
+	    project_conf_changed = true;
+	    //System.err.println("**ConfDisplay:" + conf_display[row][col].toString());
+	    conf_table.put(conf_display[row][col].toString(), value);
+	    fireTableCellUpdated(row,col+1);
+	    updateUI();
+	}
+    }
+
+    public int showProjectConf(String conf_param) {
+	conf_table_pane.setVisible(true);
+	clearPrevConfPane();
+	confContent_pane.add(conf_table_pane, BorderLayout.CENTER);
+	confContent_pane.revalidate();	
+	clearTable();
+	int j=0;
+	int row_count = 0;
+	for (int i=0; i< num_of_setting; i++){
+	    if (conf_setting[i][1].toString().matches("^("+ conf_param +").+")) {
+		row_count = row_count +1;
+		conf_display[j][0] = conf_setting[i][0];
+	    	conf_display[j][1] = conf_setting[i][1];
+	   	conf_display[j][2] = conf_table.get(conf_setting[i][1]);
+		j++;
+	    }
+	}
+	return row_count;
+    }
+      
+    public void displaySiteConf(SiteConfSetting site_conf_tmp){
+	clearPrevConfPane();
+	confContent_pane.add(site_conf_tmp, BorderLayout.CENTER);
+	try {
+	    site_conf_tmp.showText();
+	    site_conf_tmp.goTop();
+	    confContent_pane.revalidate();
+	} catch (Exception e) {
+	    e.printStackTrace();
+	}    
+     }
+    
+    public void clearPrevConfPane() {
+	confContent_pane.remove(conf_table_pane);
+	confContent_pane.remove(site_conf);
+	confContent_pane.remove(interface_conf);
+    }
+	
+   
+    private class ConfTreeListener implements TreeSelectionListener{
+	public void valueChanged (TreeSelectionEvent e){
+	    String option = conf_tree.getLastSelectedPathComponent().toString();
+	    conf_table_pane.setVisible(true);
+	    if (option == "Compile"){
+		conf_pane_name = "COMPILE";
+		display_row_count = showProjectConf(conf_pane_name);
+		inner_button_pane.removeAll();
+		inner_button_pane.setLayout(new GridLayout(1,3));
+	    } else if (option == "Tomcat"){
+		conf_pane_name ="TOMCAT";
+		display_row_count = showProjectConf(conf_pane_name);
+		//Setup Tomcat button control pane
+		inner_button_pane.removeAll();
+		inner_button_pane.setLayout(new GridLayout(1,3));
+		if (checkTomcatServer()) {
+		    changeTomcatButtonPane1();
+		} else {
+		    changeTomcatButtonPane2();
+		}
+	    } else if (option =="Proxy"){
+		conf_pane_name="PROXY";
+		display_row_count = showProjectConf(conf_pane_name);
+		//Setup Proxy button control pane
+		inner_button_pane.removeAll();
+		inner_button_pane.setLayout(new GridLayout(1,3));
+	    } else if (option == "MySQL"){
+		conf_pane_name="MYSQL";
+		display_row_count = showProjectConf(conf_pane_name);
+		// Setup MySQL button control pane
+		inner_button_pane.removeAll();
+		inner_button_pane.setLayout(new GridLayout(1,3));
+		if (checkMysqlServer()) {
+		    changeMysqlButtonPane1();
+		} else {
+		    changeMysqlButtonPane2();
+		}
+	    } else if (option == "GSDL"){
+		conf_pane_name ="GSDL";
+		display_row_count = showProjectConf(conf_pane_name);
+		inner_button_pane.removeAll();
+	    } else if (option == "SiteConfig"){
+		conf_pane_name = "SiteConfig";
+		inner_button_pane.removeAll();
+		displaySiteConf(site_conf);
+	    } else if (option == "InterfaceConfig") {
+		conf_pane_name = "InterfaceConfig";
+		inner_button_pane.removeAll();
+		displaySiteConf(interface_conf);
+	    }
+	    updateUI();
+	}
+    }
+
+    public void modeChanged (int mode){
+	return;
+    }
+
+    public void gainFocus() {
+	return;
+    }
+
+    public void changeTomcatButtonPane1 (){
+	inner_button_pane.removeAll();
+	inner_button_pane.setLayout(new GridLayout(1,2));
+	inner_button_pane.add(restart_tomcat_button);
+	inner_button_pane.add(shutdown_tomcat_button);
+	restart_tomcat_button.setEnabled (true);
+	shutdown_tomcat_button.setEnabled (true);
+	updateUI();
+    }
+    public void changeTomcatButtonPane2 (){
+	inner_button_pane.removeAll();
+	inner_button_pane.setLayout(new GridLayout(1,2));
+	inner_button_pane.add(startup_tomcat_button);
+	inner_button_pane.add(shutdown_tomcat_button);
+	startup_tomcat_button.setEnabled (true);
+	shutdown_tomcat_button.setEnabled (false);
+	updateUI();
+    }	
+    public void changeMysqlButtonPane1 (){
+	inner_button_pane.removeAll();
+	inner_button_pane.setLayout(new GridLayout(1,2));
+	inner_button_pane.add(restart_mysql_button);
+	inner_button_pane.add(shutdown_mysql_button);
+	restart_mysql_button.setEnabled (true);
+	shutdown_mysql_button.setEnabled (true);
+	updateUI();
+    }
+    public void changeMysqlButtonPane2 (){
+	inner_button_pane.removeAll();
+	inner_button_pane.setLayout(new GridLayout(1,2));
+	inner_button_pane.add(startup_mysql_button);
+	inner_button_pane.add(shutdown_mysql_button);
+	startup_mysql_button.setEnabled (true);
+	shutdown_mysql_button.setEnabled (false);
+	updateUI();
+    }	
+    public void afterDisplay(){
+	return;
+    }
+} 
+
Index: /greenstone3/trunk/src/java/org/greenstone/admin/gui/DeleteLogFilePrompt.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/admin/gui/DeleteLogFilePrompt.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/admin/gui/DeleteLogFilePrompt.java	(revision 14125)
@@ -0,0 +1,120 @@
+/**
+ *#########################################################################
+ *
+ * A component of the GAI application, part of the Greenstone digital
+ * library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * <BR><BR>
+ *
+ * Author: John Thompson, Greenstone Digital Library, University of Waikato
+ * Modified by: Chi-Yu Huang
+ *
+ * <BR><BR>
+ *
+ * Copyright (C) 1999 New Zealand Digital Library Project
+ *
+ * <BR><BR>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * <BR><BR>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * <BR><BR>
+ *
+ * You should have received a copy of the 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 org.greenstone.admin.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.net.*;
+import javax.swing.*;
+import javax.swing.event.*;
+
+/*
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.LocalLibraryServer;
+import org.greenstone.gatherer.collection.BasicCollectionConfiguration;
+import org.greenstone.gatherer.file.WorkspaceTree;  // !!! Don't like this here
+import org.greenstone.gatherer.util.ArrayTools;
+import org.greenstone.gatherer.util.StaticStrings;*/
+
+
+/** This class provides the functionality to delete current collections from the 
+ ** GSDLHOME/collect/ directory. The user chooses the collection from a list, where 
+ ** each entry also displays details about itself, confirms the delete of a collection 
+ ** by checking a checkbox then presses the ok button to actually delete the collection.
+ * @author Chi-Yu Huang, Greenstone Digital Library, University of Waikato
+ * @version 1.0
+ */
+public class DeleteLogFilePrompt 
+	extends JDialog {
+    
+    /** A reference to ourself so any inner-classes can dispose of us. */
+    private DeleteLogFilePrompt prompt = null;
+    private File log_file = null;
+
+    //A flag showing the deleting status
+    private boolean current_logfile_deleted = false;
+
+    /** The size of the delete prompt screen. */
+    static final Dimension SIZE = new Dimension(500, 500);
+
+    // Constructor.
+    public DeleteLogFilePrompt() {
+	super();
+	prompt = this;
+    }
+    
+    /** Destructor. */
+    public void destroy() {
+	prompt = null;
+    }
+
+    /** This method causes the Delete Confirmation Dialog to be displayed. 
+     * returns true if it has deleted the log file that is currently open */
+    public boolean display(File log_file) {
+	int result = JOptionPane.showConfirmDialog((Component) null, "Do you really want to delete this log file", "Delete Confirmation", JOptionPane.YES_NO_OPTION);
+	if ( result == JOptionPane.YES_OPTION) {
+	    log_file.delete();
+	    current_logfile_deleted = true;
+	    JOptionPane.showMessageDialog(prompt,log_file.getPath() + " log file has been deleted. You have to restart the action to create the log file");
+	} else if (result == JOptionPane.NO_OPTION) {
+	    current_logfile_deleted = false;
+	    JOptionPane.showMessageDialog(prompt, "Cancel deleting the " + log_file.getPath() +" log file");
+	    prompt.dispose();
+	}
+	return current_logfile_deleted;
+    }
+    
+    
+    /** Shows a delete complete prompt. 
+     * @param success A <strong>boolean</strong> indicating if the collection was successfully deleted.
+     * @see org.greenstone.gatherer.collection.Collection
+     */
+    /*public void resultPrompt(boolean success) {
+	if (success) {
+	    JOptionPane.showMessageDialog(prompt,"Selected log file has been deleted. You have to restart the action to create the log file");
+	} else {
+	    JOptionPane.showMessageDialog(prompt, "Cancel deleting the log file");
+	}
+	}*/
+    
+    /** Any implementation of ActionListener requires this method so that when an 
+     **action is performed the appropriate effect can occur.*/
+    public void actionPerformed(ActionEvent event) {
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/admin/gui/LogPane.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/admin/gui/LogPane.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/admin/gui/LogPane.java	(revision 14125)
@@ -0,0 +1,378 @@
+/**
+ *#########################################################################
+ *
+ * A component of the Gatherer application, part of the Greenstone digital
+ * library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * <BR><BR>
+ *
+ * Author: Chi-Yu Huang, Greenstone Digital Library, University of Waikato
+ * Modified: 03.2005
+ *
+ * <BR><BR>
+ *
+ * Copyright (C) 1999 New Zealand Digital Library Project
+ *
+ * <BR><BR>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * <BR><BR>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * <BR><BR>
+ *
+ * You should have received a copy of the 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 org.greenstone.admin.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.tree.*;
+
+import org.greenstone.admin.GAIManager;
+import org.greenstone.admin.GAI;
+import org.greenstone.admin.Configuration;
+
+/** The Log pane is to view the status of relevant log files in GSIII
+ * @author Chi-Yu Huang, Greenstone Digital Library, University of Waikato
+ * @version
+ */
+public class LogPane
+    extends JPanel
+    implements ActionListener {
+
+    /* The pane to demonstrate log information, including  the log files being 
+     *monitored and their content*/
+    protected JSplitPane main_log_pane = null;
+
+    /** The panel that contains a log_list */
+    private JPanel logList_pane =  null;
+
+    /** The panel that contains the log content. */
+    private JPanel logContent_pane =  null;
+
+    /** The List showing all the log files concerned. */
+    private JList log_list=null;
+
+    /** The scrollable area into which the log content is placed. */
+    private JScrollPane log_content = null;
+
+    /** The label at the top of the logList_pane. */
+    private JLabel logList_label =  null;
+
+    /** The label shown at the top of the logContent Pane. */
+    private JLabel logContent_label  =  null;
+
+    /* Log TEXT AREA*/
+    private JTextArea log_textarea = null;
+
+    // The control buttons used to manipulate log Pane
+    protected JPanel button_pane = null;
+    
+    /** Buttons */
+    private JButton reload_button = null;
+    private JButton clear_button = null;
+
+    /*The pane which contains the controls for log files */
+    private JPanel control_pane = null;
+
+    private File log_file = null;
+      
+    /** The various sizes for the screen layout*/
+    static private Dimension MIN_SIZE = new Dimension( 90,  90);
+    static private Dimension LIST_SIZE  = new Dimension(200, 450);
+    static private Dimension LOGPANE_SIZE = new Dimension (800,450);
+
+    //Constructor
+    public LogPane() {
+	
+	// create all the necessary panes
+	control_pane = new JPanel();
+	button_pane = new JPanel();
+
+	// Log_Pane
+	main_log_pane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
+	main_log_pane.setPreferredSize(LOGPANE_SIZE);
+	//log_pane.setSize(LOGPANE_SIZE);
+	
+	// Log_list
+	String[] log_files = { "Tomcat log file", "Log file 2", "Log file 3"};
+	log_list = new JList(log_files);
+	log_list.setBorder(BorderFactory.createLoweredBevelBorder());
+	log_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+	log_list.setVisibleRowCount(4);
+	log_list.setBackground (Configuration.getColor("coloring.workspace_tree_background"));
+	log_list.setForeground (Configuration.getColor("coloring.workspace_tree_foreground"));
+	log_list.addListSelectionListener(new LogListListener());
+	
+	// Log_TextArea
+	log_textarea = new JTextArea();
+	log_textarea.setEditable(false);
+		
+	// Buttons
+	ReloadButtonListener rbl = new ReloadButtonListener();
+	ClearButtonListener dbl = new ClearButtonListener();
+	ImageIcon reloadButtonIcon = new ImageIcon(GAI.images_path + "toolbarButtonGraphics/general/Refresh16.gif");
+	ImageIcon clearButtonIcon = new ImageIcon(GAI.images_path + "toolbarButtonGraphics/general/Delete16.gif");
+
+	//reload_button = new JButton("Reload", reloadButtonIcon);
+	reload_button = new JButton();
+	reload_button.addActionListener(rbl);
+	reload_button.setEnabled(false);
+	reload_button.setMnemonic(KeyEvent.VK_R);
+	reload_button.setText(GAI.dictionary.get("LogPane.Reload_Log"));
+	reload_button.setToolTipText(GAI.dictionary.get("LogPane.Reload_Log_Tooltip"));
+
+	clear_button = new JButton();
+	clear_button.addActionListener(dbl);
+	clear_button.setEnabled(false);
+	clear_button.setMnemonic(KeyEvent.VK_C);
+	clear_button.setText(GAI.dictionary.get("LogPane.Clear_Log"));
+	clear_button.setToolTipText(GAI.dictionary.get("LogPane.Clear_Log_Tooltip"));
+
+	rbl = null;
+	dbl = null;
+    }
+
+    /** Any implementation of ActionListener requires this method so that when an 
+     **action is performed the appropriate effect can occur.*/
+
+    public void actionPerformed(ActionEvent event) {
+    }
+
+
+    /** This method is callsed to actually layout the components.*/
+    public void display() {
+	// Create Components.
+	//KeyListenerImpl key_listener = new KeyListenerImpl();
+	//MouseListenerImpl mouse_listener = new MouseListenerImpl();
+	//this.addKeyListener(key_listener);
+
+	// logList_Pane
+	logList_pane = new JPanel();
+	logList_pane.setBorder(BorderFactory.createLoweredBevelBorder());
+	logList_label = new JLabel();
+	logList_label.setOpaque(true);
+	logList_label.setBackground(Configuration.getColor("coloring.workspace_heading_background"));
+	logList_label.setForeground(Configuration.getColor("coloring.workspace_heading_foreground"));
+	logList_label.setText(GAI.dictionary.get("LogPane.Log_List"));
+
+	// logContent_Pane
+	logContent_pane = new JPanel();
+	logContent_pane.setBorder(BorderFactory.createLoweredBevelBorder());
+	logContent_pane.setBackground(Configuration.getColor("coloring.workspace_selection_background"));
+	logContent_pane.setForeground(Configuration.getColor("coloring.workspace_selection_foreground"));
+	logContent_label = new JLabel();
+	logContent_label.setOpaque(true);
+	logContent_label.setBackground(Configuration.getColor("coloring.workspace_selection_background"));
+	logContent_label.setForeground(Configuration.getColor("coloring.workspace_selection_foreground"));
+	logContent_label.setText(GAI.dictionary.get("LogPane.Log_Content"));
+	
+	// TEXTAREA Layout
+	log_content = new JScrollPane(log_textarea);
+
+	// Button Layout 
+	button_pane.setLayout (new GridLayout(1,3));
+	button_pane.add(reload_button);
+	button_pane.add(clear_button);
+	
+	control_pane.setLayout (new BorderLayout());
+	//control_pane.setBorder(BorderFactory.createLoweredBevelBorder());
+	control_pane.setBorder(BorderFactory.createEmptyBorder(05,10,5,10));
+	control_pane.setPreferredSize(new Dimension(50,50));
+	control_pane.setSize(new Dimension(50,50));
+	control_pane.add (button_pane, BorderLayout.CENTER);
+
+	// Layout Components
+	logList_pane.setLayout(new BorderLayout());
+	logList_pane.add(log_list, BorderLayout.CENTER);
+	logList_pane.add(logList_label, BorderLayout.NORTH);
+		
+	logContent_pane.setLayout(new BorderLayout());
+	logContent_pane.add(log_content,BorderLayout.CENTER);
+	logContent_pane.add(logContent_label, BorderLayout.NORTH);
+	logContent_pane.add(control_pane, BorderLayout.SOUTH);
+	
+	main_log_pane.add(logList_pane, JSplitPane.LEFT);
+	main_log_pane.add(logContent_pane, JSplitPane.RIGHT);
+	main_log_pane.setDividerLocation(LIST_SIZE.width - 10);
+	
+	this.setLayout(new BorderLayout());
+	this.add(main_log_pane, BorderLayout.CENTER);
+	//this.add(control_pane, BorderLayout.SOUTH);
+    }
+
+    /** Called whenever this pane gains focus, this method ensures that the various 
+     **tree renderers are correctly colouring the tree (as these settings sometimes get lost).
+     * @param event A <strong>FocusEvent</strong> containing details about the focus action performed.
+     */
+    /*public void focusGained(FocusEvent event) {
+	DefaultTreeCellRenderer def = new DefaultTreeCellRenderer();
+	DefaultTreeCellRenderer w = (DefaultTreeCellRenderer)workspace_tree.getCellRenderer();
+	DefaultTreeCellRenderer c = (DefaultTreeCellRenderer)collection_tree.getCellRenderer();
+	if(event.getSource() == workspace_tree) {
+	    w.setBackgroundSelectionColor(def.getBackgroundSelectionColor());
+	    c.setBackgroundSelectionColor(Color.lightGray);
+	}
+	else if(event.getSource() == collection_tree) {
+	    c.setBackgroundSelectionColor(def.getBackgroundSelectionColor());
+	    w.setBackgroundSelectionColor(Color.lightGray);
+	}
+	repaint();
+	}*/
+    
+    /** Implementation side-effect, not used in any way.
+     * @param event A <strong>FocusEvent</strong> containing details about the focus action performed.
+     */
+    /*public void focusLost(FocusEvent event) {
+      }*/
+    
+    /** Called to inform this control panel that it has just gained focus as an effect of the user clicking on its tab.
+     */
+    public void gainFocus() {
+	// Update the meta-audit view to show the current selection, if any.
+	//Gatherer.g_man.meta_audit.setRecords(getCollectionTreeSelection());
+    }
+    
+    /** Called whenever the detail mode changes to ensure the filters are at an appropriate 
+     **level (ie only editable by those that understand regular expression matching)
+     * @param mode the mode level as an int
+     */
+    /*  public void modeChanged(int mode) {
+	collection_filter.setEditable(mode > Configuration.LIBRARIAN_MODE);
+	workspace_filter.setEditable(mode > Configuration.LIBRARIAN_MODE);
+	}*/
+    
+    private class KeyListenerImpl
+	extends KeyAdapter {
+	private boolean vk_left_pressed = false;
+	public void keyReleased(KeyEvent event) {
+	}
+	// we need to watch for left clicks on an unopened folder - should shift the focus to the
+	//parent folder. But because there is some other mysterious key listener that does opening and 
+	//closing folders on right and left clicks, we must detect the situation before the other handler 
+	//has done its job, and process it after.*/
+	public void keyPressed(KeyEvent event) {
+	    if (event.getKeyCode() == KeyEvent.VK_LEFT) {
+		
+	    }
+	}     
+    }
+
+    /** This class listens for mouse clicks and responds right mouse button clicks (popup menu)., left
+     **  mouse button:log file selected */
+    private class MouseListenerImpl
+	extends MouseAdapter {
+	/* Any subclass of MouseAdapter can override this method to respond to mouse click events. 
+	 *In this case we want to open a pop-up menu if we detect a right mouse click over one of our 
+	 *registered components, and start an external application if someone double clicks on a certain 
+	 *file record. */
+	public void mouseReleased(MouseEvent e) {}
+	public void mouseExited(MouseEvent e) {}
+	public void mousePressed(MouseEvent e) {}
+	public void mouseEntered(MouseEvent e) {}
+	
+    }
+    
+    /** This class serves as the listener for actions on the build button. */
+    private class ReloadButtonListener
+	implements ActionListener {
+	/** As the log files could be modified in the runtime environment
+	 *  This button is to reload the log file whenever user want to */
+	public void actionPerformed(ActionEvent event) {
+	    // Remember that for lower thresholds the above doesn't work, so try this instead
+	    reload_button.setEnabled(true);
+	    clear_button.setEnabled(true);
+	    updateLogsContent(log_file.getPath());
+	}
+    }
+    
+    private class ClearButtonListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    if (!log_file.exists()){
+		JOptionPane.showMessageDialog((Component) null,log_file.getPath() + " log file does not exist");
+		return;
+	    } else {
+		ClearLogFilePrompt cfp  = new ClearLogFilePrompt();
+		boolean file_cleared = cfp.display(log_file);
+		if (file_cleared) {
+		    log_textarea.setText("");
+		}
+	    }
+	    clear_button.setEnabled(false);
+	}
+    }
+    
+    public void updateLogsContent(String filename){
+	if (!log_file.exists()){ 
+	    log_textarea.setText("");
+	    JOptionPane.showMessageDialog((Component) null, filename+" log file does not exist");  
+	    clear_button.setEnabled(false);
+	} else {
+	    readFile(filename);
+	}
+    }
+
+    public void readFile (String filename) {
+	log_textarea.setText("");
+	String fileLine;
+	try {
+	    BufferedReader in = new BufferedReader(new FileReader(filename));
+	    while ((fileLine = in.readLine()) != null) {
+		log_textarea.append(fileLine);
+		log_textarea.append("\n");
+	    }
+	} catch (Exception e) {
+	    e.printStackTrace();
+	}	    
+    }
+   
+    private class LogListListener implements ListSelectionListener {
+	public void valueChanged (ListSelectionEvent e){
+	    if (e.getValueIsAdjusting() == false){
+		if (log_list.getSelectedIndex() == -1){
+		    //no selection
+		} else if (log_list.getSelectedIndex () == 0 ) {
+		    log_file = new File (GAI.tomcat_home+File.separatorChar+"logs"+File.separatorChar+"catalina.out");
+		    String filename = log_file.getPath();
+		    updateLogsContent(filename);
+		    reload_button.setEnabled(true);
+		    clear_button.setEnabled(true);
+		} else if (log_list.getSelectedIndex () == 1) {
+		    log_textarea.setText("");
+		    JOptionPane.showMessageDialog((Component) null,"This file has not been defined yet");	
+		    clear_button.setEnabled(false);
+		    reload_button.setEnabled(false);
+		} else if (log_list.getSelectedIndex () == 2) {
+		    log_textarea.setText("");
+		    JOptionPane.showMessageDialog((Component) null,"This file has not been defined yet");	
+		    clear_button.setEnabled(false);
+		    reload_button.setEnabled(false);
+		}
+	    }
+	}
+    }
+    public void modeChanged (int mode){
+	return;
+    }
+    public void afterDisplay() {
+	return;
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/admin/gui/MenuBar.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/admin/gui/MenuBar.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/admin/gui/MenuBar.java	(revision 14125)
@@ -0,0 +1,203 @@
+/**
+ *#########################################################################
+ *
+ * A component of the GAI application, part of the Greenstone digital
+ * library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * <BR><BR>
+ *
+ *
+ * <BR><BR>
+ *
+ * Copyright (C) 1999 New Zealand Digital Library Project
+ *
+ * <BR><BR>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * <BR><BR>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * <BR><BR>
+ * Author: Chi-Yu Huang, Greenstone Digital Library, University of Waikato
+ *
+ * You should have received a copy of the 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 org.greenstone.admin.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+
+import org.greenstone.admin.GAI;
+import org.greenstone.admin.Configuration;
+
+/** The menu bar for the Administration tools main GUI. 
+ * @author Chi-Yu Huang, Greenstone Digital Library, University of Waikato
+ * @version
+ */
+public class MenuBar
+    extends JMenuBar {
+    /** The icon to be displayed alongside the context choosen help file. */
+    private int current_tab = -1;
+    
+    private JMenu file = null;
+    private JMenu edit = null;
+    public JMenu help  = null;
+    // public JMenuItem file_cdimage    = null;
+    // public JMenuItem file_close      = null;
+    //public JMenuItem file_delete     = null;
+    public JMenuItem file_exit = null;
+    public JMenuItem file_save = null;
+    public JMenuItem help_general;
+    public JMenuItem help_conf;
+    public JMenuItem help_ext;
+    public JMenuItem help_monitor;
+    public JMenuItem help_log;
+    public JMenuItem help_about;
+
+    static public ImageIcon HELP_ICON = null; 
+    static public ImageIcon BLANK_ICON = null;
+    
+    //    public MenuBar(MenuListener Menu_listener)
+    public MenuBar(MenuListener menu_listener)
+    {
+	HELP_ICON = new ImageIcon(GAI.images_path +"help.gif");
+	BLANK_ICON = new ImageIcon(GAI.images_path+"blank.gif");
+
+	//file = new JMenu("File");
+	file = new JMenu();
+	file.setMnemonic(KeyEvent.VK_F);
+	file.setText(GAI.dictionary.get("Menu.File"));
+	
+	//file_save = new JMenuItem("Save");
+	file_save = new JMenuItem();
+	file_save.addActionListener(GAI.ga_man);
+	file_save.setMnemonic(KeyEvent.VK_S);
+	file_save.setText(GAI.dictionary.get("Menu.File_Save"));
+	
+	//file_exit = new JMenuItem("Exit");
+	file_exit = new JMenuItem();
+	file_exit.addActionListener(GAI.ga_man);
+	file_exit.setMnemonic(KeyEvent.VK_X);
+	file_exit.setText(GAI.dictionary.get("Menu.File_Exit"));
+
+	//Layout (File menu)
+	file.add(file_save);
+	file.add(new JSeparator());
+	file.add(file_exit);
+
+	// Edit menu
+	//edit = new JMenu("Edit");
+	edit = new JMenu();
+	edit.setMnemonic(KeyEvent.VK_E);
+	edit.setText(GAI.dictionary.get("Menu.Edit"));
+			  
+	// Help menu
+	//help = new JMenu("Help");
+	help = new JMenu();
+	help.setMnemonic(KeyEvent.VK_H);
+	help.setIcon(HELP_ICON);
+	help.setText(GAI.dictionary.get("Menu.Help"));
+	
+	help_general = new JMenuItem();
+	help_general.addActionListener(GAI.ga_man);
+	help_general.setText(GAI.dictionary.get("Source.General"));
+		
+	help_conf = new JMenuItem();
+	help_conf.addActionListener(GAI.ga_man);
+	help_conf.setText(GAI.dictionary.get("GAI.Configuration"));
+		
+	help_ext = new JMenuItem();
+	help_ext.addActionListener(GAI.ga_man);
+	help_ext.setText(GAI.dictionary.get("GAI.Ext"));
+	
+	help_monitor = new JMenuItem();
+	help_monitor.addActionListener(GAI.ga_man);
+	help_monitor.setText(GAI.dictionary.get("GAI.Monitor"));
+	
+	help_log = new JMenuItem();
+	help_log.addActionListener(GAI.ga_man);
+	help_log.setText(GAI.dictionary.get("GAI.Log"));
+	
+	help_about = new JMenuItem();
+	help_about.addActionListener(GAI.ga_man);
+	help_about.setText(GAI.dictionary.get("Menu.Help_About"));
+			
+	
+	// Layout (help menu)
+	help.add(help_general);
+	help.add(new JSeparator());
+	if (Configuration.get("admin.conf")) {
+	    help.add(help_conf);
+	}
+	if (Configuration.get("admin.ext")) {
+	    help.add(help_ext);
+	}
+	if (Configuration.get("admin.monitor")) {
+	    help.add(help_monitor);
+	}
+	if (Configuration.get("admin.log")) {
+	    help.add(help_log);
+	}
+	
+	help.add(new JSeparator());
+	help.add(help_about);
+
+	// Layout (menu bar)
+	add(file);
+	add(Box.createHorizontalStrut(15));
+	add(edit);
+	add(Box.createHorizontalGlue());
+	add(help);
+    }
+
+    /** Once a quit has been requested by the user, prevent any further menu selections. */
+    public void exit() {
+	file.setEnabled(false);
+	edit.setEnabled(false);
+	help.setEnabled(false);
+    }
+
+    /*public void refresh(int refresh_reason, boolean ready)
+    {
+	file_close.setEnabled(ready);
+	file_save.setEnabled(ready);
+	}*/
+
+
+    /** In order to provide context aware help advice we keep track of which
+     *  tab the user has open, and then highlight that help menu item with
+     *  separators.
+     *  @param tab_index The index of the selected tab (0-7).
+     */
+    public void tabSelected(int tab_index) {
+	JMenuItem selected;
+	if(current_tab != -1) {
+	    // Remove the image
+	    selected = help.getItem(current_tab);
+	    if(selected != null) {
+		selected.setIcon(BLANK_ICON);
+	    }
+	}
+	current_tab = tab_index + 2;
+	selected = help.getItem(current_tab);
+	if(selected != null) {
+	    selected.setIcon(HELP_ICON);
+	    
+	}
+	selected = null;
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/admin/gui/ParsingProgress.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/admin/gui/ParsingProgress.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/admin/gui/ParsingProgress.java	(revision 14125)
@@ -0,0 +1,123 @@
+/**
+ *#########################################################################
+ *
+ * A component of the Core GUI application, part of the Greenstone digital
+ * library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * <BR><BR>
+ *
+ * Author: John Thompson, Greenstone Digital Library, University of Waikato
+ *
+ * <BR><BR>
+ *
+ * Copyright (C) 1999 New Zealand Digital Library Project
+ *
+ * <BR><BR>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * <BR><BR>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * <BR><BR>
+ *
+ * You should have received a copy of the 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 org.greenstone.core;
+
+import java.awt.*;
+import java.lang.Object;
+import javax.swing.*;
+
+/** This class provides a progress bar to be displayed whenever the module 
+ * is running some background tasks
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class ParsingProgress
+    extends JDialog {
+    //implements ActionListener {
+    
+    public final static int ONE_SECOND = 1000;
+
+    /** The content pane within the dialog box. */
+    private JPanel content_pane = null;
+    private Timer timer;
+    /** The progress bar itself. */
+    private JProgressBar progressBar = null;
+    
+    /** The default size of the progress dialog. */
+    static final Dimension SIZE = new Dimension(400,75);
+    
+    
+    /** Constructor.
+     * @param title The title to show on the dialog, as a <strong>String</strong>.
+     * @param message The message to show on the dialog, as a <strong>String</strong>.
+     * @param max The total amount of the time the process is running before 
+     * the progress bar can be disposed of, as an <i>int</i>.
+     */
+    public ParsingProgress(String title, String message, int max) {
+	super();
+	this.setSize(SIZE);
+	this.setTitle(title);
+	//updateUI();
+
+	// Creation
+	this.content_pane = (JPanel) getContentPane();
+	this.content_pane = new JPanel();
+	
+	this.progressBar = new JProgressBar();
+	this.progressBar.setMaximum(max);
+	this.progressBar.setIndeterminate(true);
+       
+
+	// Layout
+	this.content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	this.content_pane.setLayout(new BorderLayout());
+	this.content_pane.add(new JLabel(message), BorderLayout.NORTH);
+	this.content_pane.add(progressBar, BorderLayout.CENTER);
+	
+	//Create a timer
+	//timer = new Timer (ONE_SECOND, new ActionListener() {
+	//	public void actionPerformed (ActionEvent evt) {
+		    progressBar.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+		    
+		    //container.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+		    /*  progressBar.setValue(max);
+			Toolkit.getDefaultToolkit().beep();
+			timer.stop();
+			startButton.setEnabled(true);
+			setCursor(null); //turn off the wait cursor
+			progressBar.setValue(progressBar.getMinimum());*/
+		    //}
+		    //});
+	
+	// Center and display
+	Dimension screen_size = Toolkit.getDefaultToolkit().getScreenSize();
+	setLocation((screen_size.width - SIZE.width) / 2,
+		    (screen_size.height - SIZE.height) / 2);
+	
+	setVisible(true);
+    }
+    
+    public void destroy() {
+    }
+    
+    /** Method which increments the progress count by one, which should be called 
+     ** after every successful parsing of a classifier or plugin.
+     */
+    public void inc() {
+	this.progressBar.setValue(progressBar.getValue() + 1);
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/admin/gui/SaveChangePrompt.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/admin/gui/SaveChangePrompt.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/admin/gui/SaveChangePrompt.java	(revision 14125)
@@ -0,0 +1,108 @@
+/**
+ *#########################################################################
+ *
+ * A component of the GAI application, part of the Greenstone digital
+ * library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * <BR><BR>
+ *
+ * Author: Chi-Yu Huang, Greenstone Digital Library, University of Waikato
+ *
+ * <BR><BR>
+ *
+ * Copyright (C) 1999 New Zealand Digital Library Project
+ *
+ * <BR><BR>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * <BR><BR>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * <BR><BR>
+ *
+ * You should have received a copy of the 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 org.greenstone.admin.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.net.*;
+import javax.swing.*;
+import javax.swing.event.*;
+
+import org.greenstone.admin.gui.ConfPane;
+
+/** This class provides the functionality to show a prompt to save changed file  
+ * @author Chi-Yu Huang, Greenstone Digital Library, University of Waikato
+ * @version 1.0
+ */
+public class SaveChangePrompt
+    extends JDialog {
+    
+    /** A reference to ourself so any inner-classes can dispose of us. */
+    private SaveChangePrompt prompt = null;
+    private File file = null;
+        
+    //A flag showing the saving change status
+    private boolean current_change_saved = false;
+    
+    /** The size of the save prompt screen. */
+    static final Dimension SIZE = new Dimension(500, 500);
+    
+    // Constructor.
+    public SaveChangePrompt() {
+	super();
+	prompt = this;
+    }
+    
+    /** Destructor. */
+    public void destroy() {
+	prompt = null;
+    }
+    
+    /** This method causes the Save Change Confirmation Dialog to be displayed.
+     * returns true if it has save the change file that is currently open */
+    // public boolean display(File file) {
+	/*int result = JOptionPane.showConfirmDialog((Component) null, "Do you really want to save the change", "Save Confirmation", JOptionPane.YES_NO_OPTION);
+	  if ( result == JOptionPane.YES_OPTION) {
+	  ConfPane confPane = new ConfPane();
+	  confPane.saveNewConfSetting();
+	  confPane.writeConfFile(file);
+	  current_change_saved = true;
+	  } else if (result == JOptionPane.NO_OPTION) {
+	    current_change_saved = false;
+	    prompt.dispose();
+	    }
+	    resultPrompt(current_change_saved);
+	    return current_change_saved;*/
+    //}
+    
+    /** Shows a save complete prompt. 
+     * @param success A <strong>boolean</strong> indicating if the collection was successfully saved
+     */
+    public void resultPrompt(boolean success) {
+	if (success) {
+	    JOptionPane.showMessageDialog(prompt,"The build property file has been saved.");
+	} else {
+	    JOptionPane.showMessageDialog(prompt, "Cancel saving the change to build property file");
+	}
+    }
+    
+    /** Any implementation of ActionListener requires this method so that when an 
+     **action is performed the appropriate effect can occur.*/
+    public void actionPerformed(ActionEvent event) {
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/admin/gui/SetServerPane.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/admin/gui/SetServerPane.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/admin/gui/SetServerPane.java	(revision 14125)
@@ -0,0 +1,371 @@
+/**
+ *#########################################################################
+ *
+ * A component of the GAI application, part of the Greenstone digital
+ * library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * <BR><BR>
+ *
+ * Author: Chi-Yu Huang, Greenstone Digital Library, University of Waikato
+ * Date: 05.2005
+ *
+ * <BR><BR>
+ *
+ * Copyright (C) 1999 New Zealand Digital Library Project
+ *
+ * <BR><BR>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * <BR><BR>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * <BR><BR>
+ *
+ * You should have received a copy of the 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 intended to confirm the initial user's setting about
+ * the Tomcat server and MySQL server they would like to run GSDL3 with
+ */
+package org.greenstone.admin.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.List;
+import java.util.ArrayList;
+import java.lang.Object;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.tree.*;
+import javax.swing.table.*;
+import java.awt.event.MouseEvent;
+import java.net.*;
+import java.sql.*;
+
+import org.greenstone.admin.Configuration;
+import org.greenstone.core.ParsingProgress;
+import org.greenstone.admin.GAI;
+
+
+/** The initial setting pane is to request the user to input the preferred 
+ * Tomcat and Mysql server,they would like to run GSDL3 with
+ *  @author Chi-Yu Huang, Greenstone Digital Library, University of Waikato
+ *  @version
+ */
+public class SetServerPane
+    extends JFrame
+    implements ActionListener {
+
+    /* This pane is to allow the user to set up their own running Tomcat/Mysql server 
+     * before the installation of the GSDL3*/
+    // protected JScrollPane setting_message_pane = null;
+    protected JPanel main_pane = null;
+    protected JPanel button_pane = null;
+    protected JPanel outter_control_pane = null;
+    protected JScrollPane setting_table_pane = null;
+    protected JTable server_setting_table = null;
+    
+    private JButton save_button = null;
+    private JButton install_button = null;
+    private JButton exit_button = null;
+
+    ServerSettingTableModel server_setting_table_model = null;
+    private boolean setting_confirm = false;
+    private ArrayList conf_array;
+    private boolean success = false;
+    private boolean file_saved = true;
+    
+    /** The various sizes for the screen layout*/
+    static private Dimension MIN_SIZE = new Dimension( 90,  90);
+    static private Dimension LIST_SIZE  = new Dimension(200, 450);
+    static private Dimension DIALOG_SIZE = new Dimension (400,300);
+    static private Dimension FRAME_SIZE = new Dimension (500, 450);
+    static private Dimension TABLE_SIZE = new Dimension(500,200);
+    static final Dimension SIZE = new Dimension(400,400);
+    
+    //Constructor
+    public SetServerPane() {
+	super();
+	this.setDefaultCloseOperation(EXIT_ON_CLOSE);
+	this.setSize(FRAME_SIZE);
+	this.setTitle("Setting Tomcat/MYSQL Servers");
+	
+	// create all the control button panes
+	button_pane  = new JPanel();
+
+	//First time running button
+	SaveButtonListener ybl = new SaveButtonListener();
+	InstallButtonListener nbl = new InstallButtonListener();
+	ExitButtonListener ebl = new ExitButtonListener();
+	
+	// ImagesIcon for the buttons
+	ImageIcon SaveButtonIcon = new ImageIcon(GAI.images_path + "refresh.gif");
+	ImageIcon InstallButtonIcon = new ImageIcon(GAI.images_path + "exit.gif");
+	ImageIcon ExitButtonIcon = new ImageIcon(GAI.images_path + "exit.gif");
+
+	save_button = new JButton("Save Setting", SaveButtonIcon);
+	save_button.addActionListener(ybl);
+	save_button.setMnemonic(KeyEvent.VK_S);
+	save_button.setToolTipText("Click this button to save up the setting");
+	save_button.setEnabled(false);
+
+	install_button = new JButton("Install GSDL3", InstallButtonIcon);
+	install_button.addActionListener(nbl);
+	install_button.setEnabled(false);
+	install_button.setMnemonic(KeyEvent.VK_I);
+	install_button.setToolTipText("Click this button to Install Greenstone III");
+
+	exit_button = new JButton("Exit Setting and Installation", ExitButtonIcon);
+	exit_button.addActionListener(ebl);
+	exit_button.setEnabled(false);
+	install_button.setMnemonic(KeyEvent.VK_I);
+	install_button.setToolTipText("Click this button to Exit the Setting and Installation of Greenstone III");
+
+	//Setting&Installation buttons
+	ybl = null;
+	nbl = null;
+	ebl = null;
+    }
+
+    /** Any implementation of ActionListener requires this method so that when an 
+     **action is performed the appropriate effect can occur.*/
+    public void actionPerformed(ActionEvent event) {
+    }
+
+    /** This method is callsed to actually layout the components.*/
+    public void display() {
+	//KeyListenerImpl key_listener = new KeyListenerImpl();
+	//MouseListenerImpl mouse_listener = new MouseListenerImpl();
+	//this.addKeyListener(key_listener);
+	
+	server_setting_table_model = new ServerSettingTableModel();
+	server_setting_table = new JTable(server_setting_table_model) {
+		protected String[] rowToolTips = {
+		    "The name of the machine that Tomcat is/will be run on",
+		    "The port number that Tomcat is/will be run on",
+		    "The base directory for the existing Tomcat installation",
+		    "The name of the machine that Mysql is/will be run on",
+		    "The port number that Mysql is/will be run on",
+		    "The base directory for the existing MYSQL installations",
+		    "The user name for the administrator of using MySQL",
+		    "The socket that Mysql is/will be run on"};
+		
+		public String getToolTipText(MouseEvent e){
+		    String tip = null;
+		    Point p = e.getPoint();
+		    int rowIndex = rowAtPoint(p);
+		    int colIndex = columnAtPoint(p);
+		    int realColumnIndex = convertColumnIndexToModel(colIndex);
+		    if (realColumnIndex == 0){
+			tip = rowToolTips[rowIndex];
+		    } else {
+			tip = super.getToolTipText(e);
+		    }
+		    return tip;
+		}
+	    };
+	
+	//Set up tableHeader
+	JTableHeader header = server_setting_table.getTableHeader();
+	header.setFont(new Font("Arial", Font.BOLD, 14));
+	
+	server_setting_table.setRowHeight(30);
+	setting_table_pane = new JScrollPane(server_setting_table);
+	
+	// Button Control Layout 
+	save_button.setEnabled(true);
+	install_button.setEnabled(true);
+	exit_button.setEnabled(true);
+	
+	button_pane.setLayout (new GridLayout(1,3));
+	button_pane.add(save_button);
+	button_pane.add(install_button);
+	button_pane.add(exit_button);
+
+	outter_control_pane = new JPanel();
+	outter_control_pane.setLayout (new BorderLayout());
+	outter_control_pane.setBorder(BorderFactory.createLoweredBevelBorder());
+	outter_control_pane.setPreferredSize(new Dimension(50,50));
+	outter_control_pane.setSize(new Dimension(50,50));
+	outter_control_pane.add (button_pane, BorderLayout.CENTER);
+	
+	main_pane = (JPanel) getContentPane();
+	main_pane.setLayout (new BorderLayout());
+	main_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	main_pane.add(setting_table_pane, BorderLayout.CENTER);
+	main_pane.add(outter_control_pane, BorderLayout.SOUTH);
+	main_pane.setBackground(Configuration.getColor("coloring.workspace_selection_background"));
+	main_pane.setForeground(Configuration.getColor("coloring.workspace_selection_foreground"));
+	
+	// Center and display
+	Dimension screen_size = Toolkit.getDefaultToolkit().getScreenSize();
+	setLocation((screen_size.width - SIZE.width) / 2,
+		    (screen_size.height - SIZE.height) / 2);
+	setVisible(true);
+    }
+    
+    public void destroy() {
+    }
+        
+    /** This class serves as the listener for actions on the build button.*/
+    private class SaveButtonListener
+	implements ActionListener {
+	/** This button is to save any change you have added
+	 ** to the Tomcat/Mysql servers setting*/
+	public void actionPerformed(ActionEvent event) {
+	    setting_confirm = true;
+	    int result = JOptionPane.showConfirmDialog((Component) null, "Do you really want to save the setting?", "Save Confirmation", JOptionPane.YES_NO_OPTION);
+	    if ( result == JOptionPane.YES_OPTION) {
+		updateSetting (GAI.build_properties_file);
+		file_saved = writeFile (GAI.build_properties_file);
+		if (file_saved) {
+		    JOptionPane.showMessageDialog((Component) null,"Change has been saved succefully!");
+		} else {
+		    JOptionPane.showMessageDialog((Component) null,"Change has not been saved succefully!");
+		    file_saved = false;
+		} 
+	    } else if (result == JOptionPane.NO_OPTION) {
+		JOptionPane.showMessageDialog((Component) null,"Change has not been saved!");
+		file_saved = false;
+	    }
+	}
+    }
+
+    public void updateSetting(File build_properties_file) {
+	readFile (GAI.build_properties_file);
+	String new_string;
+	for (int i=0; i < server_setting_table_model.getRowCount(); i++){
+	    //System.err.println("What is the value here:" + server_setting_table_model.getValueAt(i,0).toString());
+	    if (!server_setting_table_model.getValueAt(i,1).toString().matches("^\\s*$")){
+		for (int j=0; j < conf_array.size(); j++){
+		    if (((String)conf_array.get(j)).startsWith(server_setting_table_model.getValueAt(i,0).toString().toLowerCase())){
+			//System.err.println("What is the value in conf_array:" + conf_array.get(j));
+			new_string = server_setting_table_model.getValueAt(i,0).toString()+"="+server_setting_table_model.getValueAt(i,1).toString();
+			conf_array.set(j, new_string.toLowerCase());
+		    }
+		}
+	    }
+	}
+	
+    }
+    public void readFile (File build_properties_file) {
+	String filename = build_properties_file.getPath();
+	String fileLine;
+	/*conf_array[] store all the details from the build.properties*/
+	conf_array = new ArrayList();
+	try {
+	    BufferedReader conf_in = new BufferedReader(new FileReader(filename));
+	    while ((fileLine = conf_in.readLine()) != null) {
+		// Besides an empty line, all the other lines will be stored in the conf_array
+		if (!fileLine.matches("^\\s*$")) {
+		    conf_array.add(fileLine);
+		} 
+	    }
+	    conf_in.close();
+	} catch (Exception e) {
+	    e.printStackTrace();
+	}
+    }
+    
+    public boolean writeFile(File build_properties_file){
+	String filename = build_properties_file.getPath();
+	try {
+	    BufferedWriter conf_out = new BufferedWriter(new FileWriter(filename));
+	    for (int j=0 ; j < conf_array.size(); j++){
+		conf_out.write(conf_array.get(j).toString());
+		conf_out.newLine();
+	    }
+	    success = true;
+	    conf_out.close();
+	} catch (Exception e) {
+	    e.printStackTrace();
+	    success = false;
+	}
+	return success;
+    }
+
+    private class InstallButtonListener
+	implements ActionListener {
+	// Exit the Adminstration tool 
+	public void actionPerformed(ActionEvent event) {
+	    setting_confirm = false;
+	    /*if (!setting_confirm) {
+	      GAIManager gai = new GAIManager("/research/chi/gsdl3-test/gsdl3", screen_size);
+	      }*/
+	}
+    }
+    
+    private class ExitButtonListener
+	implements ActionListener {
+	// Exit the Adminstration tool 
+	public void actionPerformed(ActionEvent event) {
+	    if (!file_saved) {
+		int result = JOptionPane.showConfirmDialog((Component) null, "The value of configuration has been changed,do you really want to exit?", "Exit Confirmation", JOptionPane.YES_NO_OPTION);
+		if ( result == JOptionPane.YES_OPTION) {
+		    System.exit(1);
+		} else if (result == JOptionPane.NO_OPTION) {
+		    JOptionPane.showMessageDialog((Component) null,"Press Save button to save the change!");
+		}
+	    } else {
+		System.exit(1);
+	    }	    
+	}
+    }
+    
+    class ServerSettingTableModel extends AbstractTableModel {
+	String[] columnNames = {"Configuration Parameter",
+				"Configuration Value"};
+	Object [][] conf_display = {{"TOMCAT.SERVER", ""},
+				    {"TOMCAT.PORT", ""},
+				    {"TOMCAT.INSTALLED.PATH",""},
+				    {"MYSQL.SERVER",""},
+				    {"MYSQL.PORT",""},
+				    {"MYSQL.INSTALLED.PATH",""},
+				    {"MYSQL.ADMIN.USER",""},
+				    {"MYSQL.SOCKET",""}};
+	
+	public int getColumnCount(){
+	    return columnNames.length;
+	}
+	
+	public int getRowCount() {
+	    return conf_display.length;
+	}
+	
+	public String getColumnName(int col){
+	    return columnNames[col];
+	}
+	
+	public Object getValueAt(int row,int col){
+	    return conf_display[row][col];
+	}
+	
+	public boolean isCellEditable(int row, int col){
+	    if (col == 0){
+		return false;
+	    } else {
+		return true;
+	    }
+	}
+
+	public void setValueAt(Object value, int row, int col){
+	    conf_display[row][col] = value;
+	    fireTableCellUpdated(row,col);
+	}
+    }
+
+}
+       
+
Index: /greenstone3/trunk/src/java/org/greenstone/admin/gui/SiteConfSetting.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/admin/gui/SiteConfSetting.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/admin/gui/SiteConfSetting.java	(revision 14125)
@@ -0,0 +1,151 @@
+/**
+ *#########################################################################
+ *
+ * A component of the GAI application, part of the Greenstone digital
+ * library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * <BR><BR>
+ *
+ * Author: Chi-Yu Huang, Greenstone Digital Library, University of Waikato
+ * Modified: 03.2005
+ *
+ * <BR><BR>
+ *
+ * Copyright (C) 1999 New Zealand Digital Library Project
+ *
+ * <BR><BR>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * <BR><BR>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * <BR><BR>
+ *
+ * You should have received a copy of the 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 org.greenstone.admin.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+import java.lang.Object;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.tree.*;
+import javax.swing.table.*;
+
+import org.greenstone.admin.GAI;
+
+/*Site configuration demonstrated in XML format
+ *@author: Chi-Yu Huang, Greenstone Digital Library, University of Waikato
+ *@version:
+ */
+public class SiteConfSetting
+    extends JPanel {
+    // implements TextListener {
+
+    //The Text area to demonstarte configuration content
+    private JTextArea site_conf_content = null;
+
+    //The scrollable area into which the configuration content is placed
+    private JScrollPane site_conf_area = null;
+    
+    private String site_conf_name;
+    private boolean conf_changed = false;
+    private StringBuffer site_conf_in;
+    
+    public SiteConfSetting(String conf_name, File conf_file) {
+	super();
+	this.site_conf_name = conf_name;
+	/*A StringBuffer to store the content of Site Configuration files such as 
+	 *SiteConfig.xml and InterfaceConfig.xml files*/
+	this.site_conf_in = new StringBuffer();
+	this.site_conf_in = readConfFile(conf_file);
+	this.site_conf_content = new JTextArea();
+	this.site_conf_content.setEditable(true);
+	this.site_conf_content.append(this.site_conf_in.toString());
+	this.site_conf_area = new JScrollPane(site_conf_content);  
+	this.site_conf_content.getDocument().addDocumentListener(new ConfDocumentListener());
+	setLayout(new BorderLayout());
+	add(site_conf_area,BorderLayout.CENTER);
+    }
+    
+    private class ConfDocumentListener implements DocumentListener {
+        final String newline = "\n";
+	
+        public void insertUpdate(DocumentEvent e) {
+	    conf_changed = true;
+        }
+        
+	public void removeUpdate(DocumentEvent e) {
+	    conf_changed = true;
+	}
+	
+        public void changedUpdate(DocumentEvent e) {
+	    conf_changed = true;
+	}
+	
+        public void updateLog(DocumentEvent e, String action) {
+	}
+    }
+    
+    public boolean confChanged ()
+    {
+	return this.conf_changed;
+    }
+    
+    public void showText()
+    {
+	site_conf_content.getText();
+    }
+    
+    public void goTop()
+    {
+	//Go to the top of ScrollPane
+	site_conf_content.setCaretPosition(0);
+    }
+    
+    public void saveFile(File filename) 
+    {
+	try {
+	    BufferedWriter site_out = new BufferedWriter(new FileWriter(filename.getPath()));
+	    String text = site_conf_content.getText();
+	    site_out.write(text);
+	    site_out.close();
+	    conf_changed = false;
+	} catch (Exception e) {
+	    e.printStackTrace();
+	}
+    }
+    
+    private StringBuffer readConfFile(File filename)
+    {
+	StringBuffer file_buffer = new StringBuffer();
+	String fileLine;
+	try {
+	    BufferedReader in = new BufferedReader(new FileReader(filename));
+	    while ((fileLine = in.readLine())!= null) {
+		file_buffer.append(fileLine);
+		file_buffer.append("\n");
+	    }
+   	} catch (Exception e) {
+	    e.printStackTrace();
+	}	    
+	return file_buffer;
+    }
+
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/admin/gui/TabbedPane.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/admin/gui/TabbedPane.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/admin/gui/TabbedPane.java	(revision 14125)
@@ -0,0 +1,90 @@
+/**
+ *#########################################################################
+ *
+ * A component of the Gatherer application, part of the Greenstone digital
+ * library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Chi-Yu Huang, Greenstone Digital Library, University of Waikato
+ *
+ * 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 org.greenstone.admin.gui;
+
+
+import javax.swing.JTabbedPane;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JFrame;
+import javax.swing.JComponent;
+import java.awt.*;
+import java.awt.event.KeyEvent;
+
+public class TabbedPane extends JPanel {
+
+    private static final Dimension SIZE = new Dimension(800, 540);
+
+    public TabbedPane() {
+	super(new GridLayout(1, 1));
+	setBackground(new Color(176,208,176));
+	
+        JTabbedPane tabbedPane = new JTabbedPane();
+        JComponent panel1 = makeTextPanel("Log information Pane");
+	/*   tabbedPane.addTab("Log Pane", icon, panel1,
+	     "Log Pane");*/
+	panel1.setPreferredSize(SIZE);
+	panel1.setBackground(new Color(176,208,176));
+	tabbedPane.addTab("Log Pane", panel1);
+	tabbedPane.setMnemonicAt(0, KeyEvent.VK_L);
+      
+
+        JComponent panel2 = makeTextPanel("Runtime Status");
+        /*tabbedPane.addTab("Status Pane", icon, panel2,
+	  "Status Pane");*/
+
+	panel2.setPreferredSize(SIZE);
+	panel2.setBackground(new Color(176,208,176));
+	tabbedPane.addTab("Status Pane", panel2);
+        tabbedPane.setMnemonicAt(1, KeyEvent.VK_R);
+
+        //Add the tabbed pane to this panel.
+        add(tabbedPane);
+    }
+
+    protected JComponent makeTextPanel(String text) {
+        JPanel panel = new JPanel(false);
+        JLabel filler = new JLabel(text);
+        filler.setHorizontalAlignment(JLabel.CENTER);
+        panel.setLayout(new GridLayout(1, 1));
+        panel.add(filler);
+        return panel;
+    }
+
+    /** Returns an ImageIcon, or null if the path was invalid. */
+    protected static ImageIcon createImageIcon(String path) {
+        java.net.URL imgURL = TabbedPane.class.getResource(path);
+        if (imgURL != null) {
+            return new ImageIcon(imgURL);
+        } else {
+            System.err.println("Couldn't find file: " + path);
+            return null;
+        }
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/admin/gui/ThreadControl.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/admin/gui/ThreadControl.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/admin/gui/ThreadControl.java	(revision 14125)
@@ -0,0 +1,390 @@
+/**
+ *#########################################################################
+ *
+ * A component of the GAI application, part of the Greenstone digital
+ * library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * <BR><BR>
+ *
+ * Author: Chi-Yu Huang, Greenstone Digital Library, University of Waikato
+ *
+ * <BR><BR>
+ *
+ * Copyright (C) 1999 New Zealand Digital Library Project
+ *
+ * <BR><BR>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * <BR><BR>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * <BR><BR>
+ *
+ * You should have received a copy of the 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 org.greenstone.admin.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.net.*;
+import javax.swing.*;
+import javax.swing.event.*;
+
+import org.greenstone.admin.GAI;
+import org.greenstone.admin.GAIManager;
+import org.greenstone.admin.gui.LogPane;
+import org.greenstone.core.ParsingProgress;
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.helper.ProjectHelperImpl;
+
+
+
+public class ThreadControl 
+    extends Thread {
+    
+    private GAIManager gai_man;
+
+    public ThreadControl(){
+    }
+
+    public void run(){
+    }   
+
+    
+    public void executeAntTarget(String command_string) throws IOException  {
+	Project ant = new Project();
+	File buildFile = new File (GAI.gsdl3_src_home + File.separator + "build.xml");
+	
+	//Set up a PrintStream pointing at a file
+	//FileOutputStream ant_out =
+	//   new FileOutputStream(GAI.gsdl3_src_home + File.separator + "ant_out.log");
+	//FileOutputStream ant_err = 
+	//   new FileOutputStream(GAI.gsdl3_src_home + File.separator + "ant_err.log");
+	
+	//	BufferedOutputStream ant_out_buffer = 
+	//   new BufferedOutputStream(ant_out, 1024);
+	//BufferedOutputStream ant_err_buffer = 
+	///   new BufferedOutputStream(ant_err, 1024);
+	
+	//PrintStream ant_out_ps =
+	//   new PrintStream(ant_out_buffer, false);
+	//PrintStream ant_err_ps =
+	//   new PrintStream(ant_err_buffer, false);
+	
+	DefaultLogger log = new DefaultLogger();
+        //log.setErrorPrintStream(ant_err_ps);
+	//log.setOutputPrintStream(ant_out_ps);
+
+	log.setErrorPrintStream(System.err);
+	log.setOutputPrintStream(System.out);
+        log.setMessageOutputLevel(Project.MSG_INFO);
+	ant.addBuildListener(log);
+	try {
+	    ant.init();
+	    ant.fireBuildStarted();
+	    ProjectHelper helper = ProjectHelper.getProjectHelper();
+	    helper.parse(ant, buildFile);
+	    ant.executeTarget(command_string);
+	    ant.fireBuildFinished(null);
+	}
+	catch (BuildException e) {
+	    e.printStackTrace(System.err); 
+	    ant.fireBuildFinished(e);
+	}
+	/*finally {
+	    System.setOut(ant_out_ps);
+	    System.setErr(ant_err_ps);
+	    }*/
+
+	//boolean ant_success = checkAntResult();
+	//ant_out_ps.close();
+	//ant_err_ps.close();
+	/*if (!ant_success){
+	    int result = JOptionPane.showConfirmDialog((Component) null, "Ant building call was failed, do you want to see the log file?", "Exit Confirmation", JOptionPane.YES_NO_OPTION);
+	    if ( result == JOptionPane.YES_OPTION) {
+		//System.exit(1);
+		// Showing ant_out.log content
+	    } else if (result == JOptionPane.NO_OPTION) {
+		JOptionPane.showMessageDialog((Component) null,"You can see the log file from Log Pane!");
+	    } 
+	} else {
+	    //System.err.println("****Ant build successed");
+	    //JOptionPane.showMessageDialog((Component) null,"You can see the log file from Log Pane!");
+	    
+	    }*/
+    }
+
+    /*public boolean checkAntResult(){
+	try {
+	    String filename = GAI.gsdl3_src_home + File.separator +"ant_out.log";
+	    String fileLine;
+	    
+	    BufferedReader ant_result = new BufferedReader(new FileReader(filename));
+	    
+	    while ((fileLine = ant_result.readLine()) != null) {
+		if (fileLine.matches("BUILD SUCCESSFUL")){
+		    //return true;
+		    return false;
+		} else if (fileLine.matches("BUILD FAILED")){
+		    //System.err.println("***Ant result"+fileLine);
+		    return false;
+		}
+	    }
+	} catch (Exception e) {
+	    e.printStackTrace();
+	   
+	}	
+	return false;
+	}*/
+    
+
+    public class restartTomcatServer 
+	implements Runnable {
+	private String command_string = null;
+	/* Construct a restartTomcatServer Object*/
+	public restartTomcatServer(String command_string) {
+	    this.command_string = command_string;
+	}
+	
+	public void run() {
+	    try {
+		executeAntTarget(this.command_string);
+	    } catch(Exception e) { 
+		System.out.println(e.getMessage()); 
+	    }
+	}
+    }
+
+    public class startupTomcatServer 
+	implements Runnable {
+	private String command_string = null;
+	/* Construct a startupTomcatServer Object*/
+	public startupTomcatServer(String command_string) {
+	    this.command_string = command_string;
+	}
+	public void run() {
+	    try { 
+		executeAntTarget(this.command_string);
+	    } catch(Exception e) { 
+		System.out.println(e.getMessage()); 
+	    }
+	}
+    }
+
+    public class shutdownTomcatServer 
+	implements Runnable {
+	private String command_string = null;
+	/* Construct a shutdownTomcatServer Object*/
+	public shutdownTomcatServer(String command_string) {
+	    this.command_string = command_string;
+	}
+	public void run() {
+	    try { 
+		executeAntTarget(this.command_string);
+	    } catch(Exception e) { 
+		System.out.println(e.getMessage()); 
+	    }
+	}
+    }
+
+    public class startupMysqlServer 
+	implements Runnable {
+	private String command_string = null;
+
+	/* Construct a startupMysqlServer Object*/
+	public startupMysqlServer(String command_string) {
+	    this.command_string = command_string;
+	}
+	public void run() {
+	    try { 
+		executeAntTarget(this.command_string);
+	    } catch(Exception e) { 
+		System.out.println(e.getMessage()); 
+	    }
+	}
+    }
+
+    public class shutdownMysqlServer 
+	implements Runnable {
+	private String command_string = null;
+	/* Construct a shutdownMysqlServer Object*/
+	public shutdownMysqlServer(String command_string) {
+	    this.command_string = command_string;
+	}
+	public void run() {
+	    try { 
+		executeAntTarget(this.command_string);
+	    } catch(Exception e) { 
+		System.out.println(e.getMessage()); 
+	    }
+	}
+    }
+
+    public class restartMysqlServer 
+	implements Runnable {
+	private String command_string = null;
+	/* Construct a restartMysqlServer Object*/
+	public restartMysqlServer(String command_string) {
+	    this.command_string = command_string;
+	}
+	public void run() {
+	    try { 
+		executeAntTarget(this.command_string);
+	    } catch(Exception e) { 
+		System.out.println(e.getMessage()); 
+	    }
+	}
+    }
+
+    public class installGS3 
+	implements Runnable {
+	private String command_string = null;
+
+	/* Install GSDL3 through ant program*/
+	public installGS3(String command_string) {
+	    this.command_string = command_string;
+	}
+	public void run() {
+	    try {
+     
+		executeAntTarget(this.command_string);
+		// ant_success;
+	    } catch(Exception e) { 
+		System.out.println(e.getMessage()); 
+	    }
+	}
+    }
+
+    
+    public void destroy(){
+    }
+}
+
+
+/***
+ * This program shows how you can time a set of threads.  The main()
+ * program demonstrates the timing classes by spawning and timing a
+ * set of threads that just execute a dummy loop.
+ ***/
+/*public class ThreadTiming {
+
+    /** Times a group of threads.  Works with TimingWrapper. */
+//    public static class ThreadTimer {
+//	private boolean __resultReady;
+//	private int __monitor[], __numThreads;
+//	private long __begin, __end;
+	
+	/** Creates a ThreadTimer that can time a given number of threads. */
+//	public ThreadTimer(int numThreads) {
+//	    __monitor     = new int[1];
+//	    __monitor[0]  = 0;
+//	    __numThreads  = numThreads;
+//	    __resultReady = false;
+//	}
+	
+	/** Starts the timer when all the threads are ready to start. */
+//	public void start() {
+//    synchronized(__monitor) {
+//		if(++__monitor[0] >= __numThreads) {
+//		    __begin = System.currentTimeMillis();
+//		    __monitor.notifyAll();
+//		} else {
+//		    while(true) {
+//			try {
+//			    __monitor.wait();
+//			} catch(InterruptedException e) {
+//			    continue;
+//			}
+//			break;
+//		    }
+//		}
+//	    }
+//	}
+	
+	/** Stops the timer when the last thread is done. */
+//	public void stop() {
+//	    synchronized(__monitor) {
+//	if(--__monitor[0] <= 0) {
+//		    __end   = System.currentTimeMillis();
+//		    synchronized(this) {
+//		__resultReady = true;
+//		notify();
+//	    }
+//	}
+//   }
+//}/
+	
+	/** Calling thread waits until timing result is ready. */
+//	public synchronized void waitForResult() {
+//	    while(!__resultReady) {
+//		try {
+///	    wait();
+//	} catch(InterruptedException e) {
+//	}
+//    }
+//    __resultReady = false;
+//}
+//
+///** Returns elapsed time in milliseconds. */
+//public long getElapsedTime() {
+//	    return (__end - __begin);
+//}
+//  }
+//  
+    /** Wraps a thread so it can be timed with a group. */
+//    public static class TimingWrapper implements Runnable {
+//	private Runnable __runMe;
+//private ThreadTimer __timer;
+
+//	public TimingWrapper(Runnable runMe, ThreadTimer timer) {
+//    __runMe   = runMe;
+//    __timer   = timer;
+//}
+	
+//public void run() {
+//    // Note, this timing approach does not measure thread creation
+//    // and thread joining overhead.
+//    __timer.start();
+//    __runMe.run();
+//    __timer.stop();
+//}
+//  }
+
+
+//public static final int NUM_THREADS = 10;
+//public static final int NUM_LOOPS   = 10000000;
+    
+//   public static void main(String[] args) {
+//int thread;
+//ThreadTimer timer;
+//
+//	timer = new ThreadTimer(NUM_THREADS);
+
+	// Start a number of threads that iterate a dummy loop
+//	for(thread = 0; thread < NUM_THREADS; thread++)
+//    new Thread(new TimingWrapper(new Runnable() {
+//	    public void run() {
+//		for(int i=0; i < NUM_LOOPS; i++);
+//	    }
+//	}, timer)).start();
+//
+//timer.waitForResult();
+	
+//	System.out.println("Elapsed Seconds: " +
+//			   ((double)timer.getElapsedTime())/1000.0);
+//   }
+    
+//}*/
Index: /greenstone3/trunk/src/java/org/greenstone/anttasks/MyGetUserAndPassword.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/anttasks/MyGetUserAndPassword.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/anttasks/MyGetUserAndPassword.java	(revision 14125)
@@ -0,0 +1,235 @@
+/*
+ *    MyGetUserAndPassword.java
+ *    Copyright (C) 2005 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.anttasks;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+
+/** A new ant task to prompt the user for username and password.
+ * To use this task, the compiled class must be put in the classpath. add a taskdef line to the build.xml:
+ * <taskdef name="getuserandpassword" classname="org.greenstone.anttasks.MyGetUserAndPassword" />
+ * and call it like the following:
+ *  <getuserandpassword 
+ *       message="a message to display at the top of the dialog" 
+ *       userproperty="the name of the username property to set (optional)" 
+ *       pwordproperty="the name of the password property to set" 
+ *       username="default value for username (optional)" 
+ *       if="property name (optional)" 
+ *       unless="property name (optional)"/>
+ * the if and unless attributes are used to control whether this task runs or not. If the 'if' attribute is set, the task will only run if the specified property is defined. If the unless attribute is set, the task will only run if the property is not defined.
+*/
+
+public class MyGetUserAndPassword
+    extends org.apache.tools.ant.Task {
+    
+    private String message = null;
+    private String user_property = null;
+    private String pword_property = null;
+    private String username = null;
+    private String password = null;
+    private boolean cancelled = false;
+
+    private Dimension SIZE = new Dimension(300, 150);
+    private JButton ok_button = null;
+    private JTextField name_field = null;
+    private JPasswordField pass_field = null;
+    
+    private boolean do_the_task = true;
+    public void setMessage(String m) {
+	message = m;
+    }
+
+    /** specify a property name - the task will only execute if this property is set */
+    public void setIf(String property) {
+	String value = getProject().getProperty(property);
+	if (value== null) {
+	    do_the_task = false;
+	}
+    }
+
+    public void setPwordproperty(String p_prop) {
+	pword_property = p_prop;
+    }
+    
+    /** specify a property name - the task will only execute if this property is not set */
+    public void setUnless(String property) {
+	String value = getProject().getProperty(property);
+	if (value != null) {
+	    do_the_task = false;
+	}
+    }
+    
+    public void setUsername(String user) {
+	username = user;
+    }
+
+    public void setUserproperty(String u_prop) {
+	user_property = u_prop;
+    }
+    public void execute() throws org.apache.tools.ant.BuildException {
+	
+	if (!do_the_task) {
+	    return;
+	}
+	if (pword_property == null) {
+	    throw new org.apache.tools.ant.BuildException("pwordproperty attribute must be specified");
+	}
+	
+	JFrame hiddenFrame = new JFrame("Username and Password Hidden Frame");
+	final JDialog dialog = new JDialog(hiddenFrame, "Username and Password", true);
+	JPanel content_pane = (JPanel)dialog.getContentPane();
+	content_pane.setLayout(new BorderLayout(5,5));
+	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	dialog.setLocation(200, 300);
+	dialog.setSize(SIZE);
+	dialog.addWindowListener(new WindowAdapter() {
+		public void windowClosing(WindowEvent windowEvent) {
+		    cancelled = true;
+		    dialog.dispose();
+		} 
+	    });
+	
+	JPanel button_pane = new JPanel();
+	button_pane.setLayout(new GridLayout(1,2));
+	JPanel details_pane = new JPanel();
+	details_pane.setLayout(new BorderLayout(5,5));
+	JPanel labels_pane = new JPanel();
+	labels_pane.setLayout(new GridLayout(2,1));
+	JPanel fields_pane = new JPanel();
+	fields_pane.setLayout(new GridLayout(2,1));
+	
+        JTextArea instruction_textarea = new JTextArea();
+	instruction_textarea.setEditable(false);
+	instruction_textarea.setLineWrap(true);
+	instruction_textarea.setRows(2);
+	instruction_textarea.setWrapStyleWord(true);
+	if (message == null) {
+	    message = "Please enter your username and password";
+	}
+	instruction_textarea.setText(message);
+		
+	JLabel name_label = new JLabel("User name:");
+	name_field = new JTextField(16);
+	if (username != null) {
+	    name_field.setText(username);
+	}
+	if (user_property == null ) {
+	    name_field.setEditable(false);
+	} 
+	JLabel pass_label = new JLabel("Password:");
+	pass_field = new JPasswordField(16);
+	
+	FieldListener field_listener = new FieldListener();
+	name_field.addActionListener(field_listener);
+	name_field.getDocument().addDocumentListener(field_listener);
+	pass_field.addActionListener(field_listener);
+	pass_field.getDocument().addDocumentListener(field_listener);
+
+	ok_button = new JButton("Ok");
+	ok_button.setEnabled(false);
+	ok_button.addActionListener(new ActionListener() {
+		public void actionPerformed(ActionEvent actionEvent) {
+		    username = name_field.getText();
+		    password = new String(pass_field.getPassword());
+		    dialog.dispose();
+		}
+	    });
+		
+	JButton cancel_button = new JButton("Cancel");
+	cancel_button.addActionListener(new ActionListener() {
+		public void actionPerformed(ActionEvent actionEvent) {
+		    cancelled = true;
+		    dialog.dispose();
+		}
+	    });
+	
+	button_pane.add(ok_button);
+	button_pane.add(cancel_button);
+		
+	labels_pane.add(name_label);
+	labels_pane.add(pass_label);
+
+	fields_pane.add(name_field);
+	fields_pane.add(pass_field);
+
+	details_pane.add(labels_pane, BorderLayout.WEST);
+	details_pane.add(fields_pane, BorderLayout.CENTER);
+	
+	content_pane.add(instruction_textarea, BorderLayout.NORTH);
+	content_pane.add(details_pane, BorderLayout.CENTER);
+	content_pane.add(button_pane, BorderLayout.SOUTH);
+		
+	dialog.show();
+	hiddenFrame.dispose();
+
+	if (cancelled) {
+	    throw new org.apache.tools.ant.BuildException("Cancelled by user.");
+	}
+	
+	if (user_property != null) {
+	    getProject().setProperty(user_property, username);
+	}
+	getProject().setProperty(pword_property, password);
+	
+	
+	
+    }
+    private class FieldListener
+	implements ActionListener, DocumentListener {
+	
+	public void actionPerformed(ActionEvent actionEvent) {
+	    validateOkButton();
+	}
+	public void changedUpdate(DocumentEvent e) {
+	    
+	    validateOkButton();
+	}
+
+	public void insertUpdate(DocumentEvent e) {
+            
+	    validateOkButton();
+	}
+	
+	public void removeUpdate(DocumentEvent e) {
+            
+	    validateOkButton();
+	}
+	
+	private void validateOkButton() {
+	    if (name_field.getText().length()!=0 && 
+		pass_field.getPassword().length!=0) {		
+		ok_button.setEnabled(true);
+	    } else {
+		ok_button.setEnabled(false);
+	    }
+	}
+    }
+    
+
+    public static void main(String [] args) {
+	MyGetUserAndPassword task = new MyGetUserAndPassword();
+	task.setMessage("hi there kath");
+	task.setUserproperty("username");
+	task.setPwordproperty("password");
+	task.execute();
+
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/anttasks/MySetProxy.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/anttasks/MySetProxy.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/anttasks/MySetProxy.java	(revision 14125)
@@ -0,0 +1,70 @@
+/*
+ *    MyGetUserAndPassword.java
+ *    Copyright (C) 2005 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.anttasks;
+
+import java.net.Authenticator;
+import java.net.PasswordAuthentication;      
+
+/** A new ant task for as the setproxy task has a bug in it.
+ * To use this task, the compiled class must be put in the classpath. add a taskdef line to the build.xml:
+ * <taskdef name="mysetproxy" classname="MySetProxy" />
+ * and call it like the following:
+ *  <mysetproxy proxyhost="" proxyport="" proxyuser="" proxypassword=""/>
+*/
+public class MySetProxy 
+    extends org.apache.tools.ant.Task {
+
+    String host = null;
+    String port = null;
+    String user = null;
+    String password = null;
+
+    public void setProxyhost(String proxy_host) {
+	host = proxy_host;
+    }
+
+    public void setProxyPort(int proxy_port) {
+	port = Integer.toString(proxy_port);
+    }
+
+    public void setProxyuser(String proxy_user) {
+	user = proxy_user;
+    }
+    
+    public void setProxypassword(String proxy_password) {
+	password = proxy_password;
+    }
+
+    public void execute() {
+
+	try {
+	    System.setProperty("http.proxyType", "4");
+	    System.setProperty("http.proxyHost", host);
+	    System.setProperty("http.proxyPort", port);
+	    System.setProperty("http.proxySet", "true");
+	    Authenticator.setDefault(new Authenticator(){ 
+		    protected PasswordAuthentication getPasswordAuthentication(){ 
+			return new PasswordAuthentication(user, new String(password).toCharArray()); 
+		    } 
+		}); 
+	} catch (Exception e) {
+	    System.err.println("MySetProxy Error: couldn't set up the proxy");    
+	}
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/applet/phind/Phind.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/applet/phind/Phind.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/applet/phind/Phind.java	(revision 14125)
@@ -0,0 +1,945 @@
+/**********************************************************************
+ *
+ * Phind.java -- the Phind java applet - modified to work with gsdl3 kjdon
+ *
+ * Copyright 1997-2000 Gordon W. Paynter
+ * Copyright 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.
+ *
+ *********************************************************************/
+
+
+/*********************************************************************
+
+To use the applet, you'll need to embed it in a web page like this:
+
+<APPLET CODE="Phind.class" WIDTH=500 HEIGHT=500>
+
+  <PARAM NAME=collection  VALUE="fao.org">
+  <PARAM NAME=classifier  VALUE="1">
+  <PARAM NAME=phindcgi    VALUE="http://kowhai/cgi-bin/phindcgi">
+  <PARAM NAME=library     VALUE="http://kowhai/cgi-bin/library">
+  <PARAM NAME=backdrop    VALUE="http://kowhai/~paynter/transfer/phindtest/green1.jpg">
+  The Phind java applet.
+</APPLET>
+
+There are a bunch of other parameters; these are described in the 
+getParameters method below.  It is all done for you in Greenstone
+in the document.dm macro file (the _phindapplet_ macro).
+
+You may have problems with Java applet security.  Java applet's can only
+open socket connections (including the HTTP connections the applet uses 
+to get data) to the same server the applet was loaded from.  This means
+that your phindcgi, library, and (optional) backdrop URLs must be on the
+same machine that your web page was loaded from.
+
+**********************************************************************
+
+The applet comprises several classes:
+
+1. Phind (this file) is the applet class, loaded by the browser.
+   It also handles network connections.
+2. ResultDisplay is a Panel that sits in the applet and displays 
+   things; displays are connected in a doubly-linked list.
+3. ResultBox holds the results of a query.  Result boxes are shown
+   to the user through ResultDisplays.  Another doubly-linked list.
+4. ResultTitle acts as a caption to a ResultBox describing its contents.
+5. ResultCanvas is what the ResultBox data is drawn on.  It draws the
+   words on the screen, and handles user input from the mouse.
+6. ResultItem represents a single result object (a phrase or document).
+7. PhindTitle is for drawing backdrops in ResultDisplays.
+
+**********************************************************************/
+
+package org.greenstone.applet.phind;
+
+import java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.Choice;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.GridLayout;
+import java.awt.Image;
+import java.awt.Label;
+import java.awt.Panel;
+import java.awt.TextField;
+import java.awt.event.ActionListener;
+import java.net.URL;
+import java.io.DataInputStream;
+
+import java.net.Socket;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.io.IOException;
+
+import java.util.Vector;
+import java.util.Date;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Document;
+//import javax.xml.parsers.*;
+import org.xml.sax.InputSource;
+import org.apache.xerces.parsers.DOMParser;
+
+
+public class Phind extends java.applet.Applet 
+    implements ActionListener {
+    
+    // What is the collection called?
+    public String collection;
+
+    // Which phind classifier are we using? (There may be more than one.)
+    public String classifier;
+
+    // Internet address of phind resources
+    public String library_address, phindcgi_address;
+
+    // Initial search term
+    public String initialSearch;
+
+    // Number of phrases to retrieve at any one time
+    public int phraseBlockSize;
+
+    // Appearance parameters
+    public boolean vertical;
+    public int depth;
+
+    // Font
+    public int fontSize;
+    public String fontName;
+    public Font plainFont, boldFont;
+
+    // Do we want a background image in the applet?
+    public boolean showImage;
+    public String backdrop_address;
+    public Image backgroundImage;
+    public boolean showBorder;
+
+    // Colours
+    public Color panel_fg, panel_bg,
+	column_1_fg, column_1_bg, 
+	column_2_fg, column_2_bg,
+	highlight_fg, highlight_bg,
+	thesaurus_fg, thesaurus_bg, thesaurus_bar_fg, thesaurus_bar_bg,
+	expansion_fg, expansion_bg, expansion_bar_fg, expansion_bar_bg,
+	document_fg, document_bg, document_bar_fg, document_bar_bg,
+	message_fg, message_bg;
+    
+    // Column dimensions
+    int column_1_width, column_2_width;
+
+    // Where do we open new windows
+    String searchWindowName, documentWindowName;
+
+    // the mode of operation
+    int mode;
+    final int initMode = 0;
+    final int idleMode = 1;
+    final int searchMode = 2;
+
+    // Elements of the control panel
+    boolean showControlPanel;
+    Label titleLabel;
+    TextField wordField;
+    Button searchButton, prevButton, nextButton;
+
+    // Holders for the downloaded data
+    Panel resultPanel;
+    ResultDisplay firstDisplay, lastDisplay;
+
+    // The time at which the last query finished
+    Date lastQueryEndTime;
+
+    // lastQueryEndTime is stored to ensure a 1 second gap between a query
+    // returning and a new one beginning.  It is needed because the FAO
+    // folks in Rome have a huge lag, and frquently click several times
+    // while they wait; these clicks are turned into new queries, which
+    // they await again.  It is no elegant solution, but it seems like the
+    // easiest, given that I don't know threads.
+    // 1. The search button is easy to disable, and is disabled when a
+    //    socket connection is in progress.
+    // 2. ResutCanvas widgets can'r be similarly disabled because the
+    //    browser hides or wipes them, which looks very bad.
+    // 3. I cannot just ignore clicks on canvasses because the browser
+    //    caches the clicks while the socket connection is going on, and then
+    //    sends them through afterwards, when the canvas is accepting clicks
+    //    again.
+    // 4. Current sequence of events is to record the time the last query
+    //    ends, then whenever a click happens make sure a second has past.  if
+    //    you double-click the the first query is sent, returns, end-tie is
+    //    set, and the second (and any others made during query time) is
+    //    *immediately* processed, but since 1 second hasn't past it is
+    //    ignored.
+
+  
+    public String getAppletInfo() {
+	return "Phind by Gordon Paynter (paynter@cs.waikato.ac.nz). Copyright 1997-2000.";
+    }
+
+
+    public void init() {
+
+	mode = initMode;
+	
+	// Read applet parameters
+	getParameters();
+
+	// Initialise the user interface
+	setBackground(panel_bg);
+	lastQueryEndTime = new Date();
+
+	// fonts used to output text
+	plainFont = new Font(fontName, Font.PLAIN, fontSize);
+	boldFont  = new Font(fontName, Font.BOLD, fontSize);
+
+	// The phind applet layout manager
+	setLayout(new BorderLayout());
+
+	// Panel containing the displays is in the center of the display
+	resultPanel = new Panel();
+	if (vertical) {
+	    resultPanel.setLayout(new GridLayout(depth,1,0,2));
+	} else {
+	    System.out.println("horizontal");
+	    resultPanel.setLayout(new GridLayout(1,depth,2,0));
+	}
+	add("Center", resultPanel);
+
+	// Create ResultDisplays and place into the interface
+	ResultDisplay d1, d2 = null;
+	firstDisplay = new ResultDisplay(this, null);
+	resultPanel.add(firstDisplay);
+
+	if (depth == 1) {
+	    lastDisplay = firstDisplay;
+	} else {
+	    d1 = firstDisplay;
+	    for (int i = 2; i <= depth; i++) {
+		d2 = new ResultDisplay(this, d1);
+		resultPanel.add(d2);
+		d1 = d2;
+	    }
+	    lastDisplay = d2;
+	}
+
+	// The control panel
+	initialiseControlPanel();
+
+	// lets get started then
+	setStatus("Welcome to Phind.");
+	mode = idleMode;
+
+	// Perform initial search, if requested
+	if (initialSearch.length() > 0) {
+	    searchForWord(initialSearch);
+	}
+    }
+
+
+    // Display a message in the status bar
+    void setStatus(String status) {
+	showStatus(status);
+    }
+
+    // The user performs an action in the interface
+    /*   public boolean action(Event evt, Object arg) {
+
+	if (evt.target == searchButton) {
+	    System.out.println("evt.target==searchButton");
+	    searchForWord(getSearchTerm());
+	} else if (evt.target == wordField) {
+	    System.out.println("evt.target==wordField");
+	    searchForWord(getSearchTerm());
+	} else if (evt.target == prevButton) {
+	    shiftPrevious();
+	} else if (evt.target == nextButton) {
+	    shiftNext();
+	} else {
+	    System.out.println("unknown action: " + evt.toString() 
+			       + ", object: " + arg.toString());
+	}
+	return true;
+    }
+
+    */
+
+    public void actionPerformed(ActionEvent evt) {
+	
+	Component target = (Component)evt.getSource();
+	if (target==searchButton) {
+	    System.out.println("search button pressed");
+	    searchForWord(getSearchTerm());
+	} else if (target == wordField)  {
+	    System.out.println("word field entered");
+	    searchForWord(getSearchTerm());
+	} else if (target == prevButton) {
+	    System.out.println("prev button pressed");
+	    shiftPrevious();
+	}else if (target == nextButton) {
+	    System.out.println("prev button pressed");
+	    shiftNext();
+	} else {
+	    System.out.println("unknown action: " + evt.toString() );
+	    
+	}
+    }
+
+    // Search for a word 
+    //
+    // Called on two occasions:
+    //   when the "Search" Button is pressed, or
+    //   to perform an "initial search"
+    void searchForWord(String searchWord) {
+
+	System.err.println("in searchforword!!");
+	if (mode == idleMode) {
+	    
+	    setSearchTerm(searchWord);
+
+	    // Convert the String from UTF8 charaters into 
+	    // an encoding that is okay for a URL.
+	    searchWord = URLUTF8Encoder.encode(searchWord);
+
+	    // Look up the word
+	    if (searchWord.length() > 1) {
+		setStatus("searching for \"" + searchWord + "\""); 
+		firstDisplay.emptyContents();
+		ResultBox result = lookupPhraseOnServer(null, false, searchWord, searchWord, 2);
+
+		// if there is an error, return
+		if (result == null) {
+		    setStatus("No results for \"" + searchWord + "\""); 
+		    return;
+		}
+
+		// display the result
+		result.display = firstDisplay.display(result);
+		result.setSize(result.display.getSize());
+		result.paintAll(result.getGraphics());
+	    }
+
+	    enablePreviousAndNext();
+	}
+    }
+  
+
+    // Search for a phrase
+    //
+    // If querymode is 2, the user has clicked on a phrase.
+    // If querymode is 3, the user has requested more phrases.
+    // If querymode is 4, the user has requested more documents.
+    void searchForPhrase(ResultBox source, String key, String phrase, int queryMode) {
+
+	// System.out.println("searchForPhrase: " + key + " " + phrase + " " + queryMode);
+
+	if (mode == idleMode) {
+
+	    // If we are going to replace the first ResultDisplay, then empty it
+	    if (queryMode <= 2) {
+		if (source.display.next != null) source.display.next.emptyContents();
+	    }
+
+	    // look up the word
+	    setStatus("Searching for \"" + phrase + "\""); 
+	    ResultBox result = lookupPhraseOnServer(source, true, key, phrase, queryMode);
+	    if (result == null) {
+		setStatus("No result for \"" + phrase + "\""); 
+		return;
+	    }
+
+	    // If this is not already displayed, display it in the last free spot
+	    if (queryMode <= 2) {
+		result.display = lastDisplay.display(result);
+		result.setSize(result.display.getSize());
+		result.paintAll(result.getGraphics());
+	    }
+
+	    enablePreviousAndNext();
+	}
+    }
+
+
+    // Look up a phrase (or symbol) on the server
+    //
+    // Arguments are the source of the query (a ResultBox, or null if the
+    // query comes from hitting the search button), the key to search for
+    // (the text of a phrase or a symbol number), the phrase as a string, 
+    // and the query mode.
+    // Query modes are: 
+    //   0 = obsolete
+    //   1 = obsolete
+    //   2 = get first N phrases and URLs,
+    //   3 = get another N phrases into same window
+    //   4 = get another N documents into same window
+    //   5 = get another N thesaurus links into same window
+
+    ResultBox lookupPhraseOnServer(ResultBox source, 
+				   boolean keyKnown, String key, String phrase, 
+				   int queryMode) { 
+    	disableSearchButton();
+	mode = searchMode;
+	ResultBox r = null;
+
+	if (queryMode <= 2) {
+	    r = new ResultBox(this, collection, key, phrase, source);
+	} else if ((queryMode == 3) || (queryMode == 4) || (queryMode == 5)) {
+	    r = source;
+	}
+
+	try { 
+	    queryServer(keyKnown, key, queryMode, r);
+	} catch (Exception e) { 
+	    System.out.println("Phind query error: " + e.toString());
+	    setStatus("Query error: " + e.toString());
+	    mode = idleMode;
+	    enableSearchButton();
+	    return null;
+	}
+      
+	// The query is finished
+	setStatus(r.c.numberOfItems + " results for \"" + phrase + "\""); 
+	mode = idleMode;
+	enableSearchButton();
+	lastQueryEndTime = new Date();
+
+	return r;
+    }
+
+
+    // Query the phindcgi program
+    //
+    // Send a query (a word or symbol number) to the server
+    // and pass the response to a ResultBox.
+
+    void queryServer(boolean keyKnown, String word, int queryMode, ResultBox area) 
+	throws IOException {
+
+	// Build the query
+	String query = phindcgi_address + "c=" + collection + "&pc=" + classifier;
+
+	if (keyKnown) {
+	  query = query + "&ppnum=" + word;
+	} else {
+	  query = query + "&ppnum=0" + "&pptext=" + word;
+	}
+
+	
+	// Specify the set of results to return 
+	int first_e = 0;
+	int last_e = 0;
+	int first_d = 0;
+	int last_d = 0;
+	int first_l = 0;
+	int last_l = 0;
+
+	// the initial query
+	if (queryMode <= 2) {
+	  last_e = phraseBlockSize;
+	  last_d = phraseBlockSize;
+	  last_l = phraseBlockSize;
+	}
+
+	// add phrases to an existing result set
+	else if (queryMode == 3) {
+	  first_e = area.nextPhraseBlock * phraseBlockSize;
+	  area.nextPhraseBlock++;
+	  last_e = area.nextPhraseBlock * phraseBlockSize;
+	} 
+	
+	// add documents to existing result set
+	else if (queryMode == 4) {
+	  first_d = area.nextDocumentBlock * phraseBlockSize;
+	  area.nextDocumentBlock++;
+	  last_d = area.nextDocumentBlock * phraseBlockSize;
+	}
+
+	// add thesaurus links to existing result set
+	else if (queryMode == 5) {
+	  first_l = area.nextThesaurusLinkBlock * phraseBlockSize;
+	  area.nextThesaurusLinkBlock++;
+	  last_l = area.nextThesaurusLinkBlock * phraseBlockSize;
+	}
+
+	query = query + "&pfe=" + first_e + "&ple=" + last_e
+                      + "&pfd=" + first_d + "&pld=" + last_d
+                      + "&pfl=" + first_l + "&pll=" + last_l;
+
+	// Send the query to the phindcgi program 
+	System.out.println("1:sending query: " + query);
+	try {
+	    URL phindcgi = new URL(query);
+	    DataInputStream in = new DataInputStream(phindcgi.openStream());
+	    DOMParser parser = new DOMParser();
+	    parser.parse(new InputSource(in));
+	    Document data_doc = parser.getDocument();
+	    Element data_elem = data_doc.getDocumentElement();
+	    area.parseXML(data_elem);
+	    in.close();
+	} catch (Exception e) {
+	    System.err.println( "Error sending query to phindcgi: " + e);
+	    e.printStackTrace();
+	}
+	area.repaint();
+    }
+    
+
+    // Tidy up URLs
+    //
+    // Ensure a URL address (as string) has a protocol, host, and file.
+    //
+    // If the URL is a CGI script URL, it should be tidied up so that it is
+    // appropriate to tage attrib=value pairs on the end.  This means it
+    // must either end with a "?" or (if it contains a question-mark
+    // internally) end with a "&".
+    String tidy_URL(String address, boolean isCGI) {
+
+	// System.err.println("tidy URL: " + address);
+	
+	// make sure the URL has protocol, host, and file
+	if (address.startsWith("http")) {
+	    // the address has all the necessary components
+	} else if (address.startsWith("/")) {
+	    // there is not protocol and host
+	    URL document = getDocumentBase();
+	    String port = "";
+	    if (document.getPort()!=-1) {
+		port = ":" + document.getPort();
+	    }
+	    address = "http://" + document.getHost() + port  + address;
+	} else {
+	    // this URL is relative to the directory the document is in
+	    URL document = getDocumentBase();
+	    String directory = document.getFile();
+	    int end = directory.lastIndexOf('/');
+	    String port = "";
+	    if (document.getPort()!=-1) {
+		port = ":" + document.getPort();
+	    }
+	    directory = directory.substring(0,end + 1);
+	    address = "http://" + document.getHost() + port + directory + address;
+
+	}
+
+	// if the URL is a cgi script, make sure it has a "?" in ti,
+	// and that it ends with a "?" or "&"
+	if (isCGI) {
+	    if (address.indexOf((int) '?') == -1) { 
+		address = address + "?";
+	    } else if (!address.endsWith("?")) {
+		address = address + "&";
+	    }
+	}
+
+	return address;
+    }
+
+
+
+    // Open an arbitrary web page
+    void displayWebPage(String address, String window) {
+	try { 
+	    URL url= new URL(address);
+	    if (window.length() > 0) {
+		getAppletContext().showDocument(url, window);
+	    } else {
+		getAppletContext().showDocument(url);
+	    }
+	} catch (Exception e) { 
+	    System.out.println("Cannot open web page: " + e.toString());
+	}
+    }
+
+
+    // Get the applet parameters
+    void getParameters() {
+
+	// What is this collection called?
+	collection = parameterValue("collection");
+	System.out.println("Phind collection: " + collection);
+
+	// Which of the collection's classifiers are we using?
+	classifier = parameterValue("classifier", "1");
+	System.out.println("Phind classifier: " + classifier);
+
+	// Where is the Greenstone library
+	library_address = parameterValue("library");
+	library_address = tidy_URL(library_address, true);
+	System.out.println("Phind library: " + library_address);
+
+	// Where is the phind CGI script
+	// we assume this is relative to the greenstone library
+	phindcgi_address = parameterValue("library")+parameterValue("phindcgi");
+	phindcgi_address = tidy_URL(phindcgi_address, true);
+	System.out.println("Phind phindcgi: " + phindcgi_address);
+
+	
+	// Is there a default search term?
+	initialSearch = parameterValue("initial_search", "");
+
+	// Should we display the control panel
+	showControlPanel = true;
+	if (parameterValue("control_panel", "show").toLowerCase().equals("hide")) {
+	    showControlPanel = false;
+	}
+	
+	// Should we show a background image?
+	backdrop_address = parameterValue("backdrop", "");
+	if (backdrop_address.length() > 0) {
+	    backdrop_address = tidy_URL(backdrop_address, false);
+	    System.out.println("Phind backdrop URL: " + backdrop_address);
+
+	    try {
+		URL backdrop_url = new URL(backdrop_address);
+		backgroundImage = getImage(backdrop_url);
+		showImage = true;
+	    } catch (Exception e) { 
+		System.out.println("Phind could not load " + backdrop_address);
+		showImage = false;
+	    }
+	}
+
+	// Should we draw a border?
+	showBorder = parameterValue("border", "on").equals("off");
+
+	// Are the windows arranged vertically or horizontally
+	if (parameterValue("orientation", "vertical").toLowerCase().startsWith("hori")) {
+	    vertical = false;
+	} else {
+	    vertical = true;
+	}
+	
+	// How many phind windows are there?
+	depth = parameterValue("depth", 3);
+
+	// Result sort order
+	// Standard is "LlEeDd", expansion-first is "EeLlDd"
+	String order = parameterValue("resultorder", "standard");
+	if (!order.equals("standard")) {
+	    int next = 20;
+	    ResultItem.sortMessage = next;
+	    for (int x = 0; x < order.length(); x++) {
+		if (order.charAt(x) == ',') {
+		    next--;
+		} else if (order.charAt(x) == 'L') {
+		    ResultItem.sortLinkItem = next;
+		} else if (order.charAt(x) == 'l') {
+		    ResultItem.sortMoreLinks = next;
+		} else if (order.charAt(x) == 'E') {
+		    ResultItem.sortPhraseItem = next;
+		} else if (order.charAt(x) == 'e') {
+		    ResultItem.sortMorePhrases = next;
+		} else if (order.charAt(x) == 'D') {
+		    ResultItem.sortDocumentItem = next;
+		} else if (order.charAt(x) == 'd') {
+		    ResultItem.sortMoreDocuments = next;
+		}
+	    }
+	    System.out.println("link: " + ResultItem.sortLinkItem);
+	    System.out.println("exps: " + ResultItem.sortPhraseItem);
+	    System.out.println("docs: " + ResultItem.sortDocumentItem);
+
+	}
+
+	// How many phrases should we fetch at any given time?
+	phraseBlockSize = parameterValue("blocksize", 10);
+
+	// What font should we use?
+	fontSize = parameterValue("fontsize", 10);
+	fontName = parameterValue("fontname", "Helvetica");
+
+	// Column dimensions
+	column_1_width = parameterValue("first_column_width", 6);
+	column_2_width = parameterValue("second_column_width", column_1_width);
+	
+	// Where do we open new windows
+	searchWindowName = parameterValue("search_window", "phindsearch");
+	documentWindowName = parameterValue("document_window", "phinddoc");
+
+	// Colours
+	panel_fg = parameterValue("panel_fg", Color.black);
+	panel_bg = parameterValue("panel_bg", Color.white);
+
+	highlight_bg = parameterValue("highlight_bg", Color.yellow);
+
+	expansion_fg = parameterValue("expansion_fg", Color.black);
+	thesaurus_fg = parameterValue("thesaurus_fg", new Color(0, 100, 0));
+	document_fg = parameterValue("document_fg", Color.blue);
+
+	thesaurus_bar_fg = parameterValue("thesaurus_bar_fg", Color.black);
+	expansion_bar_fg = parameterValue("expansion_bar_fg", Color.black);
+	document_bar_fg = parameterValue("document_bar_fg", Color.black);
+
+	thesaurus_bar_bg = parameterValue("thesaurus_bar_bg", new Color(160, 160, 190));
+	expansion_bar_bg = parameterValue("expansion_bar_bg", new Color(255, 200, 200));
+	document_bar_bg = parameterValue("document_bar_bg", new Color(150, 193, 156));
+
+	column_1_fg = parameterValue("first_column_fg", Color.black);
+	column_1_bg = parameterValue("first_column_bg", new Color(235, 245, 235));
+	column_2_fg = parameterValue("second_column_fg", Color.black);
+	column_2_bg = parameterValue("second_column_bg", new Color(200, 220, 200));
+
+	message_fg = parameterValue("message_fg", Color.black);
+	message_bg = parameterValue("message_bg", Color.white);
+
+	// Colours I don't use, yet
+	// thesaurus_bg = parameterValue("thesaurus_bg", Color.white);
+	// expansion_bg = parameterValue("expansion_bg", Color.white);
+	// document_bg = parameterValue("document_bg", Color.white);
+    }
+
+    // Get the value of a parameter given its name.
+    // There are many types of parameters, hence the variety of functions.
+
+    // Get a REQUIRED string.  Stop the applet if we cannot.
+    String parameterValue(String name) {
+	try { 
+	    return getParameter(name);
+	} catch (Exception e) {
+	    System.err.println("Phind: you must give a parameter for \"" 
+			       + name + "\".  Stopping.");
+	    stop();
+	}
+	return "";
+    }
+
+    // Get an optional parameter.  Return a default if we cannot.
+    String parameterValue(String name, String defaultValue) {
+	String text = getParameter(name);
+	if (text == null) {
+	    return defaultValue;
+	}
+	System.out.println("Phind " + name + ": " + text);
+	return text;
+    }
+
+    int parameterValue(String name, int defaultValue) {
+	int value;
+	try { 
+	    value = Integer.parseInt(getParameter(name));
+	} catch (Exception e) {
+	    return defaultValue;
+	}
+	System.out.println("Phind " + name + ": " + value);
+	return value;
+    }
+
+    Color parameterValue(String name, Color defaultValue) {
+
+	String text = getParameter(name);
+	if (text == null) {
+	    return defaultValue;
+	}
+	text = text.toLowerCase();
+
+	// a number of the form "#ddffee" 
+	if (text.startsWith("#") && (text.length() == 7)) {
+	    text = text.substring(1);
+	    int r, g, b;
+	    try {
+		r = Integer.parseInt(text.substring(0,2), 16);
+		g = Integer.parseInt(text.substring(2,4), 16);
+		b = Integer.parseInt(text.substring(4), 16);
+		return new Color(r, g, b);
+	    }  catch (Exception e) {
+		return defaultValue;
+	    }
+	}
+
+	// a known Java colour string
+	else if (text.equals("black")) { return Color.black; }
+	else if (text.equals("blue")) { return Color.blue; }
+	else if (text.equals("cyan")) { return Color.cyan; }
+	else if (text.equals("darkgray")) { return Color.darkGray; }
+	else if (text.equals("gray")) { return Color.gray; }
+	else if (text.equals("green")) { return Color.green; }
+	else if (text.equals("lightgray")) { return Color.lightGray; }
+	else if (text.equals("magenta")) { return Color.magenta; }
+	else if (text.equals("orange")) { return Color.orange; }
+	else if (text.equals("pink")) { return Color.pink; }
+	else if (text.equals("red")) { return Color.red; }
+	else if (text.equals("white")) { return Color.white; }
+	else if (text.equals("yellow")) { return Color.yellow; }
+
+	return defaultValue;
+    }
+
+
+    // Control panel operations
+
+    // Initialise the control panel
+    void initialiseControlPanel() {
+	
+	if (showControlPanel) {
+	    Panel p1 = new Panel();
+	    add("North", p1);
+	    p1.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
+	    
+	    searchButton = new Button("Search");
+	    searchButton.setFont(boldFont);
+	    //searchButton.setEnabled(true);
+	    searchButton.addActionListener(this);
+	    p1.add(searchButton);
+	    
+	    Label tempLabel = new Label("  for");
+	    tempLabel.setFont(boldFont);
+	    p1.add(tempLabel);
+	    
+	    wordField = new TextField(12);
+	    wordField.setFont(boldFont);
+	    wordField.addActionListener(this);
+	    p1.add(wordField);
+	    
+	    Label temp2 = new Label("          ");
+	    p1.add(temp2);
+	    
+	    prevButton = new Button("Previous");
+	    prevButton.setFont(boldFont);
+	    prevButton.addActionListener(this);
+	    prevButton.setEnabled(false);
+	    
+	    p1.add(prevButton);
+	    
+	    nextButton = new Button("  Next  ");
+	    nextButton.setFont(boldFont);
+	    nextButton.addActionListener(this);
+	    nextButton.setEnabled(false);
+	    p1.add(nextButton);
+	    
+	}
+    }
+    
+    // Button and field functionality
+    
+    // Enable and disable the word field
+    void enableSearchButton() {
+	if (showControlPanel) {
+	    searchButton.setEnabled(true);
+	}
+    }
+    void disableSearchButton() {
+	if (showControlPanel) {
+	    searchButton.setEnabled(false);
+	}
+    }
+
+    // Get and set the search text in the wordField
+    String getSearchTerm() {
+	if (showControlPanel) {
+	    return wordField.getText();
+	} else {
+	    return initialSearch;
+	}
+    }
+    void setSearchTerm(String word) {
+	if (showControlPanel) {
+	    wordField.setText(word);
+	} 
+    }
+
+    // Enable or disable the "Previous" and "Next" buttons
+    void enablePreviousAndNext() {
+	if (showControlPanel) {
+	    Component c = firstDisplay.current;
+	    if (c.getClass().getName().endsWith("ResultBox")) {
+		if (((ResultBox) c).prevBoxExists()) {
+		    prevButton.setEnabled(true);
+		} else {
+		    prevButton.setEnabled(false);
+		}
+	    }
+	    
+	    c = lastDisplay.current;
+	    if (c.getClass().getName().endsWith("ResultBox")) {
+		if (((ResultBox) c).nextBoxExists()) {
+		    nextButton.setEnabled(true);
+		} else {
+		    nextButton.setEnabled(false);
+		}
+	    }
+	}
+    }
+
+    // Shift to previous box
+    //
+    // If the user clicks "Previous" then scroll up.
+    void shiftPrevious() {
+
+	Component c = firstDisplay.current;
+	if (c.getClass().getName().endsWith("ResultBox")) {
+
+	    ResultBox b = (ResultBox) c;
+	    if (b.prevBoxExists()) {
+		b = b.prev;
+
+		// empty all the displays
+		firstDisplay.emptyContents();
+
+		// add as many result boxes as there are displays
+		for (int i = 1 ; ((i <= depth) && (b != null)); i++) {
+		    lastDisplay.display(b);
+		    b.setSize(b.display.getSize());
+		    b.paintAll(b.getGraphics());
+		    b = b.next;
+		}
+	    }
+	}
+	enablePreviousAndNext();
+    }
+
+    // Shift to next box
+    //
+    // If the user clicks "Next" then scroll down if possible
+    void shiftNext() {
+
+	Component c = lastDisplay.current;
+	if (c.getClass().getName().endsWith("ResultBox")) {
+
+	    ResultBox b = (ResultBox) c;
+	    if (b.nextBoxExists()) {
+
+		// find the new "first" displayed box
+		c = firstDisplay.current;
+		b = (ResultBox) c;
+		b = b.next;
+
+		// empty all the displays
+		firstDisplay.emptyContents();
+
+		// add as many result boxes as there are displays
+		for (int i = 1 ; ((i <= depth) && (b != null)); i++) {
+		    lastDisplay.display(b);
+		    b.setSize(b.display.getSize());
+		    b.paintAll(b.getGraphics());
+		    b = b.next;
+		}
+	    }
+	}
+	enablePreviousAndNext();
+    }
+
+
+
+
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/applet/phind/PhindTitle.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/applet/phind/PhindTitle.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/applet/phind/PhindTitle.java	(revision 14125)
@@ -0,0 +1,84 @@
+/**********************************************************************
+ *
+ * PhindTitle.java -- backdrops to empty ResultDisplay panels.
+ *
+ * Copyright 1997-2000 Gordon W. Paynter
+ * Copyright 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.
+ *
+ *********************************************************************/
+
+
+/*********************************************************************
+
+PhindTitle is for drawing backdrops in empty ResultDisplay panels.
+
+**********************************************************************/
+package org.greenstone.applet.phind;
+//package org.nzdl.gsdl.Phind;
+
+import java.applet.Applet;
+import java.awt.Canvas;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Image;
+
+public class PhindTitle extends Canvas {
+
+    Phind phind;
+    static Image backgroundImage;
+    boolean displayInfo;
+    
+    PhindTitle(Phind p) {
+	phind = p;
+    }
+
+    public void update(Graphics g) {
+	paint(g);
+    }
+
+    public void paint(Graphics g) {
+	Dimension canvasSize = getSize();
+
+	Color fore = phind.panel_fg;
+	Color back = phind.panel_bg;
+
+	// set the screen background
+	if (phind.showImage)
+	    try {
+		g.drawImage(phind.backgroundImage, 
+			    0, 0, canvasSize.width, canvasSize.height, back, null);
+	    } catch (Exception e) {
+		System.err.println("PhindTitle paint: "  + e);
+	    }
+	else {
+	    g.setColor(back);
+	    g.fillRect(0,0, canvasSize.width, canvasSize.height);
+	}
+    }
+}
+
+ 
+
+
+
+
+
Index: /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultBox.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultBox.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultBox.java	(revision 14125)
@@ -0,0 +1,423 @@
+/**********************************************************************
+ *
+ * ResultBox.java -- a list of phrases in the Phind java interface
+ *
+ * Copyright 1997-2000 Gordon W. Paynter
+ * Copyright 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.
+ *
+ *********************************************************************/
+
+/*********************************************************************
+
+This class is used in the Phind java applet (Phind.java).
+
+A ResultBox holds the results of a query to phindcgi.  They deal mostly
+with the information content of the query, and have methods for parsing the
+input into phrase and document items.  They have little do with display:
+ResultBoxes are shown to the user through "ResultDisplay" panels, and are
+drawn using "ResultCanvas" objects.
+
+**********************************************************************/
+package org.greenstone.applet.phind;
+//package org.nzdl.gsdl.Phind;
+
+import java.awt.Panel;
+import java.awt.BorderLayout;
+import java.awt.Scrollbar;
+
+import java.awt.Label;
+import java.awt.AWTEvent;
+import java.awt.event.AdjustmentListener;
+import java.awt.event.AdjustmentEvent;
+import java.net.*;
+import java.applet.*;
+
+import java.util.Vector;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public class ResultBox extends Panel 
+    implements AdjustmentListener {
+    
+    // Objects at a "higher" level than this one
+    Phind phind;
+    ResultDisplay display;
+
+    // Surroundig objects
+    ResultBox prev, next;
+
+    // The components contained by this one.
+    ResultCanvas c;
+    ResultTitle t;
+    Scrollbar s;
+    Panel label;
+
+    // The key identifying the phrase displayed, with its text and the
+    // collection from which it is drawn
+    String searchKey, searchPhrase, searchCollection;
+    
+    // The total frequency, expansion frequency, and document frequency
+    // of the phrase
+    int numberOfOccurances;
+    int numberOfExpansions;
+    int numberOfDocuments;
+    int numberOfThesaurusLinks;
+
+    // The number of phrases and documents retrieved, and the number of
+    // times the user has requested more phrases or documents.
+    int expansionsRetrieved;
+    int documentsRetrieved;
+    int thesaurusLinksRetrieved;
+    int nextPhraseBlock;
+    int nextDocumentBlock;
+    int nextThesaurusLinkBlock;
+    
+    int mode;
+    final int initMode = 0;
+    public final int emptyMode = 1;
+    final int loadingMode = 2;
+    final int finishedMode = 3;
+
+    String buffer;
+    boolean finished;
+
+
+    // Create a ResultBox
+    // given details of the search that generated it.
+    ResultBox(Phind p, String collect, String key, String phrase, ResultBox rb) {
+
+	super();
+	mode = initMode;
+
+	phind = p;
+	display = null;
+	next = null;
+	prev = rb;
+	if (prev != null) prev.next = this;
+
+	searchKey = key;
+	searchPhrase = phrase;
+	searchCollection = collect;
+
+	numberOfOccurances = -1;
+	numberOfExpansions = -1;
+	numberOfDocuments = -1;
+	numberOfThesaurusLinks = -1;
+
+	expansionsRetrieved = 0;
+	documentsRetrieved = 0;
+	thesaurusLinksRetrieved = 0;
+
+	nextPhraseBlock = 1;
+	nextDocumentBlock = 1;
+	nextThesaurusLinkBlock = 1;
+
+
+	setLayout(new BorderLayout());
+
+	s = new Scrollbar(Scrollbar.VERTICAL);
+	disableScrollbar();
+	s.addAdjustmentListener(this);
+	add("East", s);
+
+	c = new ResultCanvas(this);
+	add("Center", c);
+
+	t = new ResultTitle(this);
+	add("North", t);
+
+	buffer = "";
+	finished = false;
+	mode = emptyMode;
+    }
+
+    static String describeContents(String phrase, String c) {
+	return( "\"" + phrase + "\" in " + c + ".");
+    }
+
+    String describeContents() {
+	return( describeContents(searchPhrase, searchCollection) );
+    }
+
+
+    // Reset the contents of the box
+    void resetBox( ) {
+	buffer = "";
+	finished = false;
+	c.resetCanvas();
+	disableScrollbar();
+	mode = emptyMode;
+    
+	numberOfExpansions = -1;
+	numberOfDocuments = -1;
+	numberOfThesaurusLinks = -1;
+
+	expansionsRetrieved = 0;
+	documentsRetrieved = 0;
+	thesaurusLinksRetrieved = 0;
+    }
+
+    void setStatus( String status ) {
+	phind.setStatus(status);
+    }
+
+    void disableScrollbar() {
+	if (s.isEnabled()) {
+	    s.setValues(0, 1, 0, 1);
+	    s.setUnitIncrement(1);
+	    s.setBlockIncrement(1);
+	    s.setEnabled(false);
+	}
+    }
+
+    // Are there displays previous to and after this?
+    public boolean prevBoxExists () {
+	return (prev != null);
+    }
+    public boolean nextBoxExists () {
+	return (next != null);
+    }
+
+    
+    // Look up a phrase
+    // Phrase lookups are passed on to the Phind applet itself.
+    void lookupPhrase(String key, String phrase, int queryMode) {
+	buffer = "";
+	finished = false;
+	phind.searchForPhrase(this, key, phrase, queryMode);
+	t.repaint();
+    }
+
+    /*   public void processEvent(AWTEvent event) {
+	//    System.out.println("event: " + event.toString());
+	if ( (event.target == s) && 
+	     ( (event.id == Event.SCROLL_ABSOLUTE) ||
+	       (event.id == Event.SCROLL_LINE_DOWN) ||
+	       (event.id == Event.SCROLL_LINE_UP) ||
+	       (event.id == Event.SCROLL_PAGE_DOWN) ||
+	       (event.id == Event.SCROLL_PAGE_UP) ) ) {
+	    c.repaint();
+	    
+	} else {
+	    super.processEvent(event);
+	}
+	} */  
+
+    public void adjustmentValueChanged(AdjustmentEvent evt) {
+	c.repaint();
+    }
+
+    void parseXML(Element data) {
+
+	//System.out.println("phinddata:"+data.toString());
+
+	//String id="", phrase="";
+	//int df=0, ef=0, lf=0, tf=0;
+	
+	searchKey = data.getAttribute("id");
+	
+	numberOfDocuments = Integer.valueOf(data.getAttribute("df")).intValue();
+	numberOfExpansions = Integer.valueOf(data.getAttribute("ef")).intValue();
+	numberOfThesaurusLinks = Integer.valueOf(data.getAttribute("lf")).intValue();
+	numberOfOccurances = Integer.valueOf(data.getAttribute("tf")).intValue();
+
+	//searchPhrase = "cat"; // for now
+
+	// go through children
+	Node e = data.getFirstChild();
+	while (e!=null) {
+	    String node_name = e.getNodeName();
+	    if (node_name.equals("phrase")) {
+		// the value of the phrase
+		searchPhrase = getNodeText(e);
+	    } else if (node_name.equals("expansionList")) {
+		
+		NodeList expansions = ((Element)e).getElementsByTagName("expansion");
+		for (int i=0; i<expansions.getLength(); i++) {
+		    processExpansionElement((Element)expansions.item(i));
+		}
+	    } else if (node_name.equals("documentList")) {
+			
+		NodeList documents = ((Element)e).getElementsByTagName("document");
+		for (int i=0; i<documents.getLength(); i++) {
+		    processDocumentElement((Element)documents.item(i));
+		}
+	
+	
+	    } else if (node_name.equals("thesaurusList")) {
+				
+		NodeList thesaurai = ((Element)e).getElementsByTagName("thesaurus");
+		for (int i=0; i<thesaurai.getLength(); i++) {
+		    processThesaurusElement((Element)thesaurai.item(i));
+		}
+		
+	    } else {
+		System.out.println("error in phinddata format, have unwanted node, "+node_name);
+	    }
+	    e = e.getNextSibling();
+	}
+	// finished parsing, update the getMoreDocs markers
+	c.updateMarkers();
+    }
+
+
+    /** Add an expansion tag
+     *
+     * Given a string containing an XML expansion element of the form:
+     *   <expansion num="3" id="8421" prefix="PEOPLE and" suffix="" tf="3" df="3"><suffix></suffix><prefix>PEOPLE</prefix></expansion>
+     *
+     * Create a new ResultItemPhrase for display
+     *
+     *  Return true if successful, otherwise false. */
+    boolean processExpansionElement(Element e) {
+
+	String num = "", id = "", tf = "", df = "", 
+	    prefix = "", body = "", suffix = "";
+
+	body = searchPhrase;
+
+	id = e.getAttribute("id");
+	tf = e.getAttribute("tf");
+	df = e.getAttribute("df");
+	num = e.getAttribute("num");
+
+	// get prefix child
+	Node prefix_node = getChildByTagName(e, "prefix");
+	if (prefix_node!=null) {
+	    prefix = getNodeText(prefix_node);
+	}
+	Node suffix_node = getChildByTagName(e, "suffix");
+	if (suffix_node !=null) {
+	    suffix = getNodeText(suffix_node);
+	}
+
+	ResultItemPhrase ri = new ResultItemPhrase(id, tf, df, prefix, body, suffix);
+	
+	if (c.addResultItem(ri)) {
+	    expansionsRetrieved++;
+	    return true;
+	}
+	
+	return false;
+    }
+
+    /** Add a document tag
+     *
+     * Given an XML Element of the form:
+     *   <document num="2" hash="HASH424e64b811fdad933be69c" freq="1"><title>CONTENTS</title></document>
+     *
+     * Create a new ResultItemDocument for display
+     *
+     * Return true if successful, otherwise false. */
+
+    boolean processDocumentElement(Element d ) {
+	// why do we have num??
+	String num = "", hash = "", freq = "", title = "";
+
+	num = d.getAttribute("num");
+	freq = d.getAttribute("freq");
+	hash = d.getAttribute("hash");
+
+	Node title_node = getChildByTagName(d, "title");
+	if (title_node != null) {
+	    title = getNodeText(title_node);
+	}
+	// Create a new ResultItem and add it to the display
+	ResultItemDocument ri = new ResultItemDocument(hash, title, freq);
+	
+	if (c.addResultItem(ri)) {
+	    documentsRetrieved++;
+	    return true;
+	}
+	
+	return false;
+    }
+
+    /** Add a thesaurus tag
+     *
+     * Given an  XML element  of the form:
+     *
+     * <thesaurus num="3" id="36506" tf="0" df="0" type="RT"><phrase>ANGLOPHONE AFRICA</phrase></thesaurus>
+     *
+     * Create a new ResultItemLink for display
+     *
+     * Return true if successful, otherwise false. */
+
+    boolean processThesaurusElement(Element t ) {
+	
+	// why do we have num??? - not used anywhere
+	String num = "", id = "", tf = "", df = "", type = "", phrase = "";
+
+	id = t.getAttribute("id");
+	tf = t.getAttribute("tf");
+	df = t.getAttribute("df");
+	type = t.getAttribute("type");
+	num = t.getAttribute("num");
+
+	Node phrase_node = getChildByTagName(t, "phrase");
+	if (phrase_node !=null) {
+	    phrase = getNodeText(phrase_node);
+	}
+	// Create a new ResultItem and add it to the display
+	ResultItemLink ri = new ResultItemLink(id, phrase, type, tf, df);
+
+	if (c.addResultItem(ri)) {
+	    thesaurusLinksRetrieved++;
+	    return true;
+	}
+	
+	return false;
+    }
+
+    /** extracts the text out of a node */
+    protected String getNodeText(Node elem) {
+	elem.normalize();
+	Node n = elem.getFirstChild();
+	while (n!=null && n.getNodeType() !=Node.TEXT_NODE) {
+	    n=n.getNextSibling();
+	}
+	if (n==null) { // no text node
+	    return "";
+	}
+	return n.getNodeValue();
+    }
+
+    /** returns the (first) child element with the given name */
+    protected Node getChildByTagName(Node n, String name) {
+
+	Node child = n.getFirstChild();
+	while (child!=null) {
+	    if (child.getNodeName().equals(name)) {
+		return child;
+	    }
+	    child = child.getNextSibling();
+	}
+	return null; //not found
+    }
+
+
+}
+
+
+
+
Index: /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultCanvas.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultCanvas.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultCanvas.java	(revision 14125)
@@ -0,0 +1,647 @@
+/**********************************************************************
+ *
+ * ResultCanvas.java -- a Canvas onto which a phrase list is drawn
+ *
+ * Copyright 1997-2000 Gordon W. Paynter
+ * Copyright 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.
+ *
+ *********************************************************************/
+
+/*********************************************************************
+
+This class is used in the Phind java applet (Phind.java).
+
+The results of a query are displayed on a ResultCanvas object.  Each 
+entry in the result list is stored in a ResultItem, and the ResultCanvas 
+contains a Vector of ResultItems.
+
+Each ResultCanvas is embedded in a ResultBox alongside a Scrollbar.  
+When the ResultCanvas is drawn, it looks at the scrollbar, calculates 
+which ResultItems are visible, then draws them on the screen.
+
+**********************************************************************/
+
+package org.greenstone.applet.phind;
+//package org.nzdl.gsdl.Phind;
+
+import java.awt.Canvas;
+import java.awt.Scrollbar;
+import java.awt.Graphics;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Dimension;
+import java.awt.Color;
+import java.util.Vector;
+import java.awt.Image;
+//import java.awt.Event;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseAdapter;
+import java.net.URL;
+import java.applet.Applet;
+import java.util.Date;
+
+public class ResultCanvas extends Canvas {
+    
+
+    // Other objects associated with this 
+    Phind phind;
+    ResultBox parent;
+    Scrollbar scrollbar;
+    
+    // fonts and font spacings to use
+    Font areaPlain, areaBold;
+    int lineSpacing;
+    
+    // The items to display on this canvas
+    int numberOfItems;
+    int firstItemDisplayed;
+    int itemSelected;
+    Vector items;
+    
+    // the background image
+    public static Image backgroundImage;
+    
+    
+    // Create a ResultCanvas from the ResultBox which is its parent.
+    ResultCanvas(ResultBox p) {
+	
+	parent = p;
+	phind = p.phind;
+	scrollbar = p.s;
+	parent.disableScrollbar();
+
+	areaPlain = phind.plainFont;
+	areaBold  = phind.boldFont;
+
+	lineSpacing = phind.fontSize + 2;
+
+	items = new Vector();
+	numberOfItems = 0;
+	firstItemDisplayed = 0;
+	itemSelected = -1;
+    
+	if (backgroundImage == null) {
+	    backgroundImage = p.phind.backgroundImage;
+	}
+
+	// add a mouse listener for the mouse clicks. we only want to override
+	// one method, so we use the adaptor class
+	addMouseListener(new MouseAdapter() {
+		public void mouseClicked(MouseEvent evt) {
+		    ResultCanvas.this.mouseClicked(evt);
+		}
+	    });
+	
+
+    }
+
+    void resetCanvas( ) {
+	items.removeAllElements();
+	numberOfItems = 0;
+	repaint();
+    }
+
+
+    // Add a new search result.
+    // Return true if successful, otherwise false.
+    boolean addResultItem( ResultItem item ) {
+ 
+	// Add a new result, in sorted order.
+	// First sort key is item kind (lowest first),
+	// second is frequency (highest first).
+	// This is not efficient, but I don't care right now.
+	int index = 0;
+	while ((index < numberOfItems) &&
+	       ((item.sort < ((ResultItem) items.elementAt(index)).sort) ||
+		((item.sort == ((ResultItem) items.elementAt(index)).sort) &&
+		 (item.frequency <= ((ResultItem) items.elementAt(index)).frequency)))) {
+	    index++;
+	}
+	items.insertElementAt(item,index);
+	numberOfItems++;
+	return true;
+    }
+
+
+    // Update more phrases/documents/links markers
+    void updateMarkers() {
+	updateMorePhrasesMarker();
+	updateMoreDocumentsMarker();
+	updateMoreLinksMarker();
+    }
+
+    // Make sure the more Phrases item only appears in the list
+    // if it is meant to.
+    void updateMorePhrasesMarker() {
+    
+	 System.out.println("updateMorePhrasesMarker() ");
+	 System.out.println("expansions retrieved = "+parent.expansionsRetrieved +" num expansions = "+parent.numberOfExpansions);
+	// look for a marker
+	boolean found = false;
+	int index = 0;
+	while (!found && (index < numberOfItems)) {
+	    if (((ResultItem) items.elementAt(index)).isMorePhrases()) {
+		found = true;
+	    } else {
+		index++;
+	    }
+	}
+
+	if (parent.expansionsRetrieved == parent.numberOfExpansions) {
+	    // there should be no marker
+	    if (found) {
+		items.removeElementAt(index);
+		numberOfItems--;
+	    }
+
+	} else if (parent.expansionsRetrieved < parent.numberOfExpansions) {
+	    if (!found) {
+		ResultItem ri = new ResultItem(ResultItem.morePhrases);
+		addResultItem(ri);
+	    }
+	}
+    }
+
+
+    // Make sure the more documents marker appears when required
+    void updateMoreDocumentsMarker() {
+    
+	// System.out.println("updateMoreDocumentsMarker() ");
+
+	// look for a marker
+	boolean found = false;
+	int index = 0;
+	while (!found && (index < numberOfItems)) {
+	    if (((ResultItem) items.elementAt(index)).isMoreDocuments()) {
+		found = true;
+	    } else {
+		index++;
+	    }
+	}
+
+	if (parent.documentsRetrieved == parent.numberOfDocuments) {
+	    // there should be no marker
+	    if (found) {
+		items.removeElementAt(index);
+		numberOfItems--;
+	    }
+
+	} else if (parent.documentsRetrieved < parent.numberOfDocuments) {
+	    // there should be a marker
+	    if (!found) {
+		ResultItem ri = new ResultItem(ResultItem.moreDocuments);
+		addResultItem(ri);
+	    }
+	}
+    }
+
+      
+    // Make sure the more links marker appears when required
+    void updateMoreLinksMarker() {
+    
+	// System.out.println("updateMoreLinksMarker() ");
+
+	// look for a marker
+	boolean found = false;
+	int index = 0;
+	while (!found && (index < numberOfItems)) {
+	    if (((ResultItem) items.elementAt(index)).isMoreLinks()) {
+		found = true;
+	    } else {
+		index++;
+	    }
+	}
+
+	if (parent.thesaurusLinksRetrieved == parent.numberOfThesaurusLinks) {
+	    // there should be no marker
+	    if (found) {
+		items.removeElementAt(index);
+		numberOfItems--;
+	    }
+
+	} else if (parent.thesaurusLinksRetrieved < parent.numberOfThesaurusLinks) {
+	    // there should be a marker
+	    if (!found) {
+		ResultItem ri = new ResultItem(ResultItem.moreLinks);
+		addResultItem(ri);
+	    }
+	}
+    }
+
+      
+
+ 
+
+
+    public void update(Graphics g) {
+	paint(g);
+    }
+
+    public void paint(Graphics g) {
+
+	// calculate the canvas size, margins, and spacing
+	
+	// Note: the size() method is deprecated, but getSize fails in NetScape 4
+	Dimension canvasSize = getSize();
+	
+	g.setFont(areaPlain);
+	int space = g.getFontMetrics().stringWidth(" ");
+	int nought = g.getFontMetrics().stringWidth("0");
+
+	int firstColumnWidth = phind.column_1_width * nought;
+	int secondColumnWidth = phind.column_2_width * nought;
+	int columnWidth = firstColumnWidth + secondColumnWidth;
+
+	int firstColumnLeft = canvasSize.width - columnWidth;
+	int secondColumnLeft = firstColumnLeft + firstColumnWidth;
+
+	int mainLeftMargin = 0;
+	int mainRightMargin = firstColumnLeft;
+
+	// the number of items that will fit on the canvas
+	int visible = canvasSize.height / lineSpacing;
+
+	// calculate the first item to output
+	int scrollValue = scrollbar.getValue();
+	if (numberOfItems <= visible) {
+	    scrollValue = 0;
+	} else if (scrollValue > (numberOfItems - visible)) {
+	    scrollValue = numberOfItems - visible;
+	} 
+	firstItemDisplayed = scrollValue;
+
+	// Draw the phrase area
+	Color fore = phind.panel_fg;
+	Color back = phind.panel_bg;
+
+
+	// draw the background
+	if (phind.showImage) {
+	    try {
+		g.drawImage(backgroundImage, 
+			    mainLeftMargin, 0, mainRightMargin, canvasSize.height, 
+			    back, null);
+	    } catch (Exception e) {
+		phind.showImage = false;
+		System.err.println("ResultCanvas paint error: " + e); 
+		g.setColor(back);
+		g.fillRect(0, 0, canvasSize.width, canvasSize.height);
+	    }
+	} else {
+	    g.setColor(back);
+	    g.fillRect(0, 0, canvasSize.width, canvasSize.height);
+	}
+    
+	// If there are no phrases, output a brief explanation.
+	if (numberOfItems == 0) {
+	    g.drawString("No phrases match this query.", mainLeftMargin + 10, lineSpacing);
+	}
+
+	// Output each of the visible ResultItems
+	ResultItem result;
+	int tab, i, y = 0;
+	int center = mainLeftMargin 
+	    + ((mainRightMargin - mainLeftMargin 
+		- g.getFontMetrics().stringWidth(parent.searchPhrase)) / 2);
+	int thesColumn = mainLeftMargin + firstColumnWidth 
+	    + g.getFontMetrics().stringWidth("Narrower term");
+
+	String body, prefix, suffix;
+	
+	for (i = scrollValue; 
+	     (i < numberOfItems) && (y + lineSpacing < canvasSize.height); i++) {
+
+	    // Get the resultItem to output
+	    result = (ResultItem) items.elementAt(i);
+	    
+	    // Graphics settings for drawing this line
+	    y += lineSpacing;
+	    g.setFont(areaPlain);
+
+	    // Highlight the selected phrase.
+	    if (i == itemSelected) {
+		g.setColor(phind.highlight_bg);
+		g.fillRect(mainLeftMargin, y-lineSpacing+2, mainRightMargin, lineSpacing);
+	    }
+
+	    // Draw the item
+
+	    // Draw a phrase item
+	    if (result.isPhrase()) {
+		prefix = result.prefixText();
+		body = result.mainText();
+		suffix = result.suffixText();
+		
+		g.setColor(phind.expansion_fg);
+		g.setFont(areaPlain);
+		tab = center - g.getFontMetrics().stringWidth(prefix) - space;
+		g.drawString(prefix, tab, y);
+		
+		g.setFont(areaBold);
+		g.drawString(body, center, y);
+		
+		tab = center + space + g.getFontMetrics().stringWidth(body);
+		g.setFont(areaPlain);
+		g.drawString(suffix, tab, y);
+	
+	    } 
+
+	    // Draw a document item
+	    else if (result.isDocument()){
+		body = result.mainText();
+
+		g.setColor(phind.document_fg);
+		g.setFont(areaPlain);
+		tab = (mainRightMargin - g.getFontMetrics().stringWidth(body)) / 2;
+		g.drawString(body, tab, y);
+      
+	    } 
+	
+	    // Draw a thesaurus link item
+	    else if (result.isLink()){
+		prefix = result.prefixText() + ":";
+		body = result.mainText();
+		tab = thesColumn - g.getFontMetrics().stringWidth(prefix) - space;
+
+		g.setColor(phind.thesaurus_fg);
+		g.setFont(areaPlain);
+		g.drawString(prefix, tab, y);
+		g.setFont(areaBold);
+		g.drawString(body, thesColumn, y);
+	    } 
+	    
+	    // Draw a "more phrases/documents/links" marker
+	    else if (result.isMorePhrases() 
+		     || result.isMoreDocuments() 
+		     || result.isMoreLinks()){
+		body = result.mainText();
+		
+		if (result.isMorePhrases()) {
+		    g.setColor(phind.expansion_bar_bg);
+		} else if (result.isMoreDocuments()) {
+		    g.setColor(phind.document_bar_bg);
+		} else {
+		    g.setColor(phind.thesaurus_bar_bg);		    
+		}
+		g.fillRect(mainLeftMargin, y-lineSpacing+2, mainRightMargin, lineSpacing);
+
+		if (result.isMorePhrases()) {
+		    g.setColor(phind.expansion_bar_fg);
+		} else if (result.isMoreDocuments()) {
+		    g.setColor(phind.document_bar_fg);
+		} else {
+		    g.setColor(phind.thesaurus_bar_fg);		    
+		}
+		g.setFont(areaPlain);
+		tab = (mainRightMargin - g.getFontMetrics().stringWidth(body)) / 2;
+		g.drawString(body, tab, y);
+	    } 
+	}
+
+	// Draw the frequecy columns
+
+	// column backgrounds
+	g.setColor(phind.column_1_bg);
+	g.fillRect(firstColumnLeft, 0, firstColumnWidth, canvasSize.height);
+	g.setColor(phind.column_2_bg);
+	g.fillRect(secondColumnLeft, 0, secondColumnWidth, canvasSize.height);
+
+	// fill in the numbers
+	g.setColor(phind.column_1_fg);
+	g.setFont(areaPlain);
+	y = 0;
+	String docsText, freqText;
+
+	for (i = scrollValue; 
+	     (i < numberOfItems) && (y + lineSpacing < canvasSize.height); i++) {
+	    
+	    // Get the resultItem to output
+	    result = (ResultItem) items.elementAt(i);
+	    docsText = result.docsText();
+	    freqText = result.freqText();
+	    
+	    // Graphics settings for drawing this line
+	    y += lineSpacing;
+
+	    // Write the document frequency
+	    if (docsText.length() > 0) {
+		tab = secondColumnLeft - space - g.getFontMetrics().stringWidth(docsText);
+		g.drawString(docsText, tab, y);
+	    }
+
+	    // Write the term frequency
+	    if (freqText.length() > 0) {
+		tab = secondColumnLeft + secondColumnWidth 
+		    - space - g.getFontMetrics().stringWidth(freqText);
+		g.drawString(freqText, tab, y);
+	    }
+	}
+
+	// Adjust the scrollbar
+	if (visible >= numberOfItems) {
+	    parent.disableScrollbar();
+	} else {
+	    scrollbar.setValues(scrollValue, visible, 0, numberOfItems);
+	    // Deprecated - setPageIncrement() has been replaced by
+	    // setBlockIncrement(), but the latter doesn't work on some
+	    // browsers.  Damn.
+	    scrollbar.setBlockIncrement(visible - 1);
+	    //scrollbar.setPageIncrement(visible - 1);
+	    // Deprecated - more nonsense: enable() has been replaced by
+	    // setEnabled(true), but this doesn't work on some browsers.
+	    scrollbar.setEnabled(true);
+	    //scrollbar.enable();
+	}
+
+	
+	// draw the border
+	if (phind.showBorder) {
+	    g.setColor(phind.panel_fg);
+	    g.drawRect(0,0, canvasSize.width - 1, canvasSize.height - 1);
+	}
+    }
+
+    // handle mouse clicks in the new way. just copy gordons thing for now
+    public void mouseClicked(MouseEvent event) {
+
+	// ignore actions that occur within 1 second of the last
+	Date now = new Date();
+	// System.out.println("Click time: " + now.toString());
+	if (now.getTime() < (phind.lastQueryEndTime.getTime() + 1000)) {
+	    System.out.println("Ignoring click - too close to last query.");
+	    return;
+	}
+
+	// which Item is selected?
+	int rowSelected = event.getY() / lineSpacing;
+	itemSelected = rowSelected + firstItemDisplayed;
+	ResultItem item = (ResultItem) items.elementAt(itemSelected);
+
+	if (itemSelected <= numberOfItems) {
+	    
+	    //User clicks on a phrase
+	    if (item.isPhrase()) {
+		itemSelected = itemSelected;
+		update(getGraphics());
+		parent.lookupPhrase(item.hiddenText(), item.toString(), 2);
+		
+		// If meta key is held down, send query to search engine
+		/*if (event.metaDown() && !phind.library_address.equals("")) {
+		    String address = phind.library_address  
+			+ "a=q&sa=text&c=" + phind.collection
+			+ "&q=%22" + item.toString().replace(' ', '+') + "%22";
+		    phind.displayWebPage(address, phind.searchWindowName);
+		    }*/
+	    } 
+	    
+	    // Click on a thesaurus link
+	    else if (item.isLink()) {
+		itemSelected = itemSelected;
+		update(getGraphics());
+		parent.lookupPhrase(item.hiddenText(), item.toString(), 2);
+		
+		// If meta key is held down, send query to search engine
+		/*if (event.metaDown() && !phind.library_address.equals("")) {
+		    String address = phind.library_address  
+			+ "a=q&sa=text&c=" + phind.collection
+			+ "&q=%22" + item.toString().replace(' ', '+') + "%22";
+		    phind.displayWebPage(address, phind.searchWindowName);
+		    }*/
+	    } 
+	    
+	    // The user clicks on a URL; display it.
+	    else if (item.isDocument()) {
+		itemSelected = itemSelected;
+		update(getGraphics());
+		
+		String address = phind.library_address 
+		    + "a=d&c=" + phind.collection 
+		    + "&d=" + item.hiddenText()
+		    + "&q=" + parent.searchPhrase.replace(' ', '+');
+		
+		phind.displayWebPage(address, phind.documentWindowName);
+	    }
+	    
+	    // When the user clicks on "get more phrases" or other marker,
+	    // we have to send a new query to the host
+	    else if (item.isMorePhrases()){
+		parent.lookupPhrase(parent.searchKey, parent.searchPhrase, 3);
+	    } else if (item.isMoreDocuments()){
+		parent.lookupPhrase(parent.searchKey, parent.searchPhrase, 4);
+	    } else if (item.isMoreLinks()){
+		parent.lookupPhrase(parent.searchKey, parent.searchPhrase, 5);
+		
+		
+	    }
+	    repaint();
+	}
+    }
+    
+
+    // User interaction
+    //
+    // All interaction with the ResultCanvas is therough mouse clicks, and
+    // is handles in this method.  Note we ignore clicks that follow
+    // another too closely to avoid problems with slow connections.
+    /*  public boolean processEvent(Event event) {
+    
+	if (event.id == Event.MOUSE_UP) {
+
+	    // ignore actions that occur within 1 second of the last
+	    Date now = new Date();
+	    // System.out.println("Click time: " + now.toString());
+	    if (now.getTime() < (phind.lastQueryEndTime.getTime() + 1000)) {
+		System.out.println("Ignoring click - too close to last query.");
+		return true;
+	    }
+
+	    // which Item is selected?
+	    int rowSelected = event.y / lineSpacing;
+	    itemSelected = rowSelected + firstItemDisplayed;
+	    ResultItem item = (ResultItem) items.elementAt(itemSelected);
+
+	    if (itemSelected <= numberOfItems) {
+	
+		//User clicks on a phrase
+		if (item.isPhrase()) {
+		    itemSelected = itemSelected;
+		    update(getGraphics());
+		    parent.lookupPhrase(item.hiddenText(), item.toString(), 2);
+
+		    // If meta key is held down, send query to search engine
+		    if (event.metaDown() && !phind.library_address.equals("")) {
+			String address = phind.library_address  
+			    + "a=q&sa=text&c=" + phind.collection
+			    + "&q=%22" + item.toString().replace(' ', '+') + "%22";
+			phind.displayWebPage(address, phind.searchWindowName);
+		    }
+		} 
+
+		// Click on a thesaurus link
+		else if (item.isLink()) {
+		    itemSelected = itemSelected;
+		    update(getGraphics());
+		    parent.lookupPhrase(item.hiddenText(), item.toString(), 2);
+
+		    // If meta key is held down, send query to search engine
+		    if (event.metaDown() && !phind.library_address.equals("")) {
+			String address = phind.library_address  
+			    + "a=q&sa=text&c=" + phind.collection
+			    + "&q=%22" + item.toString().replace(' ', '+') + "%22";
+			phind.displayWebPage(address, phind.searchWindowName);
+		    }
+		} 
+
+		// The user clicks on a URL; display it.
+		else if (item.isDocument()) {
+		    itemSelected = itemSelected;
+		    update(getGraphics());
+
+		    String address = phind.library_address 
+			+ "a=r&c=" + phind.collection 
+			+ "&r=" + item.hiddenText()
+			+ "&q=" + parent.searchPhrase.replace(' ', '+');
+
+		    phind.displayWebPage(address, phind.documentWindowName);
+		}
+		 
+		// When the user clicks on "get more phrases" or other marker,
+		// we have to send a new query to the host
+		else if (item.isMorePhrases()){
+		    parent.lookupPhrase(parent.searchKey, parent.searchPhrase, 3);
+		} else if (item.isMoreDocuments()){
+		    parent.lookupPhrase(parent.searchKey, parent.searchPhrase, 4);
+		} else if (item.isMoreLinks()){
+		    parent.lookupPhrase(parent.searchKey, parent.searchPhrase, 5);
+
+
+		}
+		repaint();
+	    }
+	}
+	return true;
+	} */   
+  
+}
+
+
+
Index: /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultDisplay.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultDisplay.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultDisplay.java	(revision 14125)
@@ -0,0 +1,126 @@
+/**********************************************************************
+ *
+ * ResultDisplay.java -- Phrase list holder for Phind java applet
+ *
+ * Copyright 1997-2000 Gordon W. Paynter
+ * Copyright 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.
+ *
+ *********************************************************************/
+
+/*********************************************************************
+
+This class is used in the Phind java applet (Phind.java).
+
+A ResultDisplay is a Panel that can display a single Component, which will
+be a ResultBox or PhindTitle object.
+
+ResultBoxes can be "chained" together with their "prev" and "next" fields,
+allowing us to have an arbitrary number of "displays" in which to show
+phrase lists.
+
+Main methods:
+* emptyContents will remove the component and emptyAll the "next" display
+* display will add an item to the first (ie: most "prev") available box
+
+**********************************************************************/
+package org.greenstone.applet.phind;
+//package org.nzdl.gsdl.Phind;
+
+import java.awt.Panel;
+import java.awt.BorderLayout;
+import java.awt.Component;
+
+class ResultDisplay extends Panel {
+
+  Phind phind;
+  ResultDisplay prev, next;
+  Component current;
+  boolean empty;
+
+  // Create a new Display
+  ResultDisplay(Phind ph, ResultDisplay pr) {
+    phind = ph;
+    prev = pr;
+    next = null;
+    if (prev != null) prev.next = this;
+    setLayout(new BorderLayout());
+
+    empty = true;
+    current = new PhindTitle(ph);
+    add(current);
+  }
+
+  // Empty the contents of the display,
+  // and all the next displays
+  void emptyContents() {
+    if (empty == false) {
+      empty = true;
+      current = new PhindTitle(phind);
+      removeAll();
+      add(current);
+    }
+    if (next != null) next.emptyContents();
+  }
+
+  // Set the contents of this display
+  Component setContents( Component r ) {
+    removeAll();
+    add("Center", r);
+    current = r;
+    empty = false;
+    if (r.getClass().getName().equals("ResultBox")) {
+      ((ResultBox) r).display = this;
+    }
+    return r;
+  }
+
+
+  
+  // Display a component in the "most previous" display
+  ResultDisplay display( Component r ) {
+
+    if (prev == null) {
+      // if there is no previous box, add the component here
+      setContents(r);
+      return this;
+
+    } else if (prev.empty == true) {
+      // if the previous box is empty, add the component to it instead
+      return prev.display(r);
+
+    } else if (empty == true) {
+      // if this box is empty, add the compnent to it
+      setContents(r);
+      return this;
+
+    } else {
+      // if this box is occupied,
+      // shift it's contents prev-wards and add here.
+      prev.display(current);
+      setContents(r);
+      return this;
+    }
+  }
+
+}
+
+
+
Index: /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultItem.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultItem.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultItem.java	(revision 14125)
@@ -0,0 +1,128 @@
+/**********************************************************************
+ *
+ * ResultItemDocument.java -- a result in the Phind applet
+ *
+ * Copyright 2000 Gordon W. Paynter
+ * Copyright 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.
+ *
+ *********************************************************************/
+
+/*********************************************************************
+
+This class is used in the Phind java applet (Phind.java).
+
+A result item holds the data describing a single line returned from a phind
+query.  The complex functionality of phrase and URL items is implemented in
+subclasses; the base class handles simpler cases like the "get more phrases" 
+marker.
+
+**********************************************************************/
+package org.greenstone.applet.phind;
+//package org.nzdl.gsdl.Phind;
+
+public class ResultItem {
+
+    // A text string describing the item
+    String text = "Generic ResultItem";
+
+    // There are several kinds of ResultItem, identified by their
+    // "kind" field, which has an integer value from the list below.
+    final static int message = 8;
+    final static int linkItem = 7;
+    final static int moreLinks = 6;
+    final static int phraseItem = 5;
+    final static int morePhrases = 4;
+    final static int documentItem = 3;
+    final static int moreDocuments = 2;
+    final static int unknownResultItem = 1;
+
+    // The kind of the item
+    int kind = unknownResultItem;
+
+    // When results are displayed, they are loosely sorted by their
+    // kind.  The user can change the sort order numbers with the 
+    // ResultOrder parameter in Phind.java.
+    static int sortMessage = 8;
+    static int sortLinkItem = 7;
+    static int sortMoreLinks = 6;
+    static int sortPhraseItem = 5;
+    static int sortMorePhrases = 4;
+    static int sortDocumentItem = 3;
+    static int sortMoreDocuments = 2;
+    static int sortUnknownResultItem = 1;
+
+    // the primary sort key
+    int sort = 0;
+    
+    // The frequency of the item (secondary sort key)
+    int frequency = 0;
+
+
+    // Create a blank ResultItem
+    ResultItem() {
+	text = "Unknown result type";
+	kind = unknownResultItem;
+	frequency = 0;
+    }
+
+    // Create a new ResultItem of some given kind
+    ResultItem(int newKind) {
+	kind = newKind;
+	frequency = 0;
+
+	if (kind == moreLinks) {
+	    text = "get more thesaurus links";
+	    sort = sortMoreLinks;
+	} else if (kind == morePhrases) {
+	    text = "get more phrases";
+	    sort = sortMorePhrases;
+	} else if (kind == moreDocuments) {
+	    text = "get more documents";
+	    sort = sortMoreDocuments;
+	} else {
+	    text = "Unknown result type";
+	    sort = sortUnknownResultItem;
+	}
+    }
+
+    // Test the type of a ResultItem
+    public boolean isLink() { return false; }
+    public boolean isMoreLinks() { return (kind == moreLinks); }
+    public boolean isPhrase() { return false; }
+    public boolean isMorePhrases() { return (kind == morePhrases); }
+    public boolean isDocument() { return false; }
+    public boolean isMoreDocuments() { return (kind == moreDocuments); }
+
+    // Return the bare text of the item
+    public String toString() { return(text.trim()); }
+
+    // Return the text of the item components
+    public String mainText() { return text; }
+    public String freqText() { 
+	if (frequency > 0) { return Integer.toString(frequency); } 
+	else { return ""; }
+    }
+    public String docsText() { return ""; }
+    public String prefixText() { return ""; }
+    public String suffixText() { return ""; }
+    public String hiddenText() { return ""; }
+}
+
Index: /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultItemDocument.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultItemDocument.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultItemDocument.java	(revision 14125)
@@ -0,0 +1,70 @@
+/**********************************************************************
+ *
+ * ResultItemDocument.java -- a document result in the Phind applet
+ *
+ * Copyright 1997-2000 Gordon W. Paynter
+ * Copyright 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.
+ *
+ *********************************************************************/
+
+/*********************************************************************
+
+This class is used in the Phind java applet (Phind.java).
+
+It contains information describing a document in which a search term 
+occurs.
+
+**********************************************************************/
+package org.greenstone.applet.phind;
+//package org.nzdl.gsdl.Phind;
+
+public class ResultItemDocument extends ResultItem {
+
+    // The document's title is stored in the superclasses 
+    // text variable, and the number of times the phrase occurs
+    // in the frequency variable. 
+
+    // The document's unique object identifier (hash value).
+    String hash;
+
+    // Create a ResultItem for a document
+    ResultItemDocument(String newHash, String newTitle, String newFrequency) {
+	
+	kind = documentItem;
+	text = newTitle;
+
+	sort = sortDocumentItem;
+	frequency = Integer.valueOf(newFrequency).intValue();
+	hash = newHash;
+    }
+
+    // Is this item a document?
+    public boolean isDocument() { return true; }
+
+    // Return the bare text of the item
+    public String toString() { return(text); }
+
+    // Return the text of the item components
+    public String hiddenText() { return hash; }
+ 
+
+}
+
Index: /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultItemLink.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultItemLink.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultItemLink.java	(revision 14125)
@@ -0,0 +1,88 @@
+/**********************************************************************
+ *
+ * ResultItemLink.java -- a thesaurus link in the Phind applet
+ *
+ * Copyright 2000 Gordon W. Paynter
+ * Copyright 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.
+ *
+ *********************************************************************/
+
+/*********************************************************************
+
+This class is used in the Phind java applet (Phind.java).
+
+It contains information describing a thesaurus link.
+
+**********************************************************************/
+package org.greenstone.applet.phind;
+//package org.nzdl.gsdl.Phind;
+
+public class ResultItemLink extends ResultItem {
+
+    // The phrase number, stored as a string and as a number
+    String id;
+    int symbol;
+
+    // The text of the link is stored in the inherited text field.
+
+    // The type of thesaurus link
+    String linkType;
+
+    // The total frequency is stored in the inherited frequency field.
+
+    // The document frequency of the thesaurus item
+    int documentFrequency;
+
+    // Create a ResultItem for a thesaurus link
+    ResultItemLink(String newId, String newText, String newLinkType, 
+		   String tf, String df) { 
+
+	kind = linkItem;
+	id = newId;
+	symbol = Integer.valueOf(newId).intValue();
+	text = newText.trim();
+	sort = sortLinkItem;
+	linkType = newLinkType;
+	frequency = Integer.valueOf(tf).intValue();
+	documentFrequency = Integer.valueOf(df).intValue();
+    }
+
+    // Is this item a phrase?
+    public boolean isLink() { return true; }
+
+    // Return the text of the item components
+    public String hiddenText() { return id; }
+    public String docsText() { 
+	if (documentFrequency <= 0) { return ""; }
+	else { return Integer.toString(documentFrequency); }
+    }
+    public String prefixText() { 
+	if (linkType.equals("RT")) { return "Related term"; }
+	else if (linkType.equals("BT")) { return "Broader term"; }
+	else if (linkType.equals("NT")) { return "Narrower term"; }
+	else if (linkType.equals("USE")) { return "Use"; }
+	else if (linkType.startsWith("UF")) { return "Used for"; }
+	else { return linkType; }
+    }
+}
+
+
+
Index: /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultItemPhrase.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultItemPhrase.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultItemPhrase.java	(revision 14125)
@@ -0,0 +1,85 @@
+/**********************************************************************
+ *
+ * ResultItemPhrase.java -- a phrase result in the Phind applet
+ *
+ * Copyright 2000 Gordon W. Paynter
+ * Copyright 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.
+ *
+ *********************************************************************/
+
+/*********************************************************************
+
+This class is used in the Phind java applet (Phind.java).
+
+It contains information describing a phrase.
+
+**********************************************************************/
+
+//package org.nzdl.gsdl.Phind;
+package org.greenstone.applet.phind;
+public class ResultItemPhrase extends ResultItem {
+
+    // The phrase number, stored as a string and as a number
+    String id;
+    int symbol;
+
+    // The text of the phrase is split into a prefix, body, and suffix.
+    // The body is the same as the parent phrase (or search term) and 
+    // the prefix and suffix are the surrounding text.
+    String prefix;
+    String body;
+    String suffix;
+
+    // The document frequency of the phrase
+    int documentFrequency;
+
+    // Create a ResultItem for a phrase
+    ResultItemPhrase(String newId, String tf, String df, 
+		     String p, String b, String s) {
+
+	kind = phraseItem;
+
+	id = newId;
+	symbol = Integer.valueOf(newId).intValue();
+
+	sort = sortPhraseItem;
+	frequency = Integer.valueOf(tf).intValue();
+	documentFrequency = Integer.valueOf(df).intValue();
+
+	prefix = p;
+	body = b;
+	suffix = s;
+	text = (prefix + " " + body + " " + suffix);
+
+    }
+
+    // Is this item a phrase?
+    public boolean isPhrase() { return true; }
+
+    // Return the text of the item components
+    public String mainText() { return body; }
+    public String docsText() { return Integer.toString(documentFrequency); }
+    public String prefixText() { return prefix; }
+    public String suffixText() { return suffix; }
+    public String hiddenText() { return id; }
+
+}
+
Index: /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultTitle.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultTitle.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/applet/phind/ResultTitle.java	(revision 14125)
@@ -0,0 +1,162 @@
+/**********************************************************************
+ *
+ * ResultTitle.java -- describe the contents of a ResultBox
+ *
+ * Copyright 1997-2000 Gordon W. Paynter
+ * Copyright 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.
+ *
+ *********************************************************************/
+
+/*********************************************************************
+
+This class is used in the Phind java applet (Phind.java).
+
+ResultTitle is part of the result list displayed to the user.  It lists the
+phrase in the Result box, the number of expansions it occurs in, and the
+number of documents it occurs in.
+
+**********************************************************************/
+
+//package org.nzdl.gsdl.Phind;
+package org.greenstone.applet.phind;
+import java.awt.Canvas;
+import java.awt.Graphics;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Dimension;
+import java.awt.Color;
+
+
+public class ResultTitle extends Canvas {
+    
+    // Other objects associated with this 
+    Phind phind;
+    ResultBox parent;
+    ResultCanvas canvas;
+
+    // fonts and font spacings to use
+    Font plain, bold;
+    Graphics g;
+    
+    // Create a ResultTitle from the ResultBox which is its parent.
+    ResultTitle(ResultBox p) {
+	
+	parent = p;
+	phind = p.phind;
+	canvas = p.c;
+	g = getGraphics();
+	
+	plain = phind.plainFont;
+	bold  = phind.boldFont;
+	
+	// Note: the size() and resize() methods are deprecated, but the newer
+	// getSize() and setSize() methods fail in NetScape 4
+	Dimension d = getSize();
+	d.height = phind.fontSize + 10;
+	setSize(d);
+	
+	
+    }
+    
+    public void update(Graphics g) {
+	paint(g);
+    }
+    
+    public void paint(Graphics g) {
+	
+	// calculate the canvas size, margins, and spacing
+	Dimension canvasSize = getSize();
+	
+	g.setFont(plain);
+	int margin = g.getFontMetrics().stringWidth(" 8888 ");
+	int y = phind.fontSize + 5;
+	
+	int rightMargin = canvas.getSize().width;
+	int secondColumn = rightMargin - margin;
+	int firstColumn = secondColumn - margin;
+	
+	g.setColor(Color.white);
+	g.fillRect(0, 0, canvasSize.width, canvasSize.height);
+	g.setColor(Color.black);
+    
+    
+	// What is the phrase we are searching for?
+	String phrase = parent.searchPhrase.replace('+', ' ');
+	
+	// Construct the description phrase
+	String links = "";
+	if (parent.numberOfThesaurusLinks <= 0) {
+	    links = "";
+	} else if (parent.numberOfThesaurusLinks == 1) { 
+	    links = "1 link";
+	} else if (parent.thesaurusLinksRetrieved == parent.numberOfThesaurusLinks) {
+	    links = parent.numberOfThesaurusLinks + " links";
+	} else {
+	    links = parent.thesaurusLinksRetrieved + " of " 
+		+ parent.numberOfThesaurusLinks + " links";
+	}
+	
+	String expansions = "";
+	if (parent.numberOfExpansions <= 0) {
+	    expansions = "no phrases";
+	} else if (parent.numberOfExpansions == 1) { 
+	    expansions = "1 phrase";
+	} else if (parent.expansionsRetrieved == parent.numberOfExpansions) {
+	    expansions = parent.numberOfExpansions + " phrases";
+	} else {
+	    expansions = parent.expansionsRetrieved + " of " 
+		+ parent.numberOfExpansions + " phrases";
+	}
+	
+	String documents = "";
+	if (parent.numberOfDocuments <= 0) { 
+	    documents = "no documents";
+	} else if (parent.documentsRetrieved == 1) {
+	    documents = "1 document";
+	} else if (parent.documentsRetrieved == parent.numberOfDocuments) {
+	    documents = parent.numberOfDocuments + " documents";
+	} else {
+	    documents = parent.documentsRetrieved + " of " 
+		+ parent.numberOfDocuments + " documents";
+	}
+	
+	String status = "(";
+	if (parent.numberOfThesaurusLinks > 0) {
+	    status = status + links + ", ";
+	} 
+	status = status + expansions + ", " + documents + ")";
+	
+	
+	// Draw the text 
+	g.setFont(bold);
+	g.drawString(phrase, 0, y);
+	int tab = g.getFontMetrics().stringWidth(phrase + "  ");
+	
+	g.setFont(plain);
+	g.drawString(status, tab, y);
+	tab = tab + g.getFontMetrics().stringWidth(status);
+	
+	if (tab < firstColumn) {
+	    g.drawString("docs", firstColumn, y);
+	    g.drawString("freq", secondColumn, y);
+	}
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/applet/phind/URLUTF8Encoder.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/applet/phind/URLUTF8Encoder.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/applet/phind/URLUTF8Encoder.java	(revision 14125)
@@ -0,0 +1,159 @@
+/**********************************************************************
+ *
+ *
+ * URLUTF8Encoder.java -- encode UTF8 String into a URL form
+ *
+ * W3C SOFTWARE NOTICE AND LICENSE
+ *
+ * Copyright (C) 1994-2000 World Wide Web Consortium, 
+ * (Massachusetts Institute of Technology, Institut National de 
+ * Recherche en Informatique et en Automatique, Keio University). 
+ * All Rights Reserved.  http://www.w3.org/Consortium/Legal/
+ * 
+ * This W3C work (including software, documents, or other related items) is
+ * being provided by the copyright holders under the following license. By
+ * obtaining, using and/or copying this work, you (the licensee) agree that
+ * you have read, understood, and will comply with the following terms and
+ * conditions:
+ * 
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation, with or without modification, for any purpose and without
+ * fee or royalty is hereby granted, provided that you include the following
+ * on ALL copies of the software and documentation or portions thereof,
+ * including modifications, that you make:
+ * 
+ *   1. The full text of this NOTICE in a location viewable to users of the
+ *      redistributed or derivative work.
+ * 
+ *   2. Any pre-existing intellectual property disclaimers, notices, or terms
+ *      and conditions. If none exist, a short notice of the following form
+ *      (hypertext is preferred, text is permitted) should be used within the
+ *      body of any redistributed or derivative code: "Copyright (C)
+ *      [$date-of-software] World Wide Web Consortium, (Massachusetts
+ *      Institute of Technology, Institut National de Recherche en
+ *      Informatique et en Automatique, Keio University). All Rights
+ *      Reserved. http://www.w3.org/Consortium/Legal/"
+ * 
+ *   3. Notice of any changes or modifications to the W3C files, including the
+ *      date changes were made. (We recommend you provide URIs to the location
+ *      from which the code is derived.)
+ * 
+ * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS
+ * MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT
+ * NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
+ * PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE
+ * ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
+ * 
+ * COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR
+ * CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR
+ * DOCUMENTATION.
+ * 
+ * The name and trademarks of copyright holders may NOT be used in advertising
+ * or publicity pertaining to the software without specific, written prior
+ * permission. Title to copyright in this software and any associated
+ * documentation will at all times remain with copyright holders.
+ *
+ *********************************************************************/
+
+/**
+ * Provides a method to encode any string into a URL-safe
+ * form, the so-called "x-www-form-urlencoded" form.
+ * Non-ASCII characters are first encoded as sequences of
+ * two or three bytes, using the UTF-8 algorithm, before being
+ * encoded in "x-www-form-urlencoded".
+ */
+
+//package org.nzdl.gsdl.Phind;
+package org.greenstone.applet.phind;
+public class URLUTF8Encoder
+{
+
+  final static String[] hex = {
+    "%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", "%21", "%22", "%23", "%24", "%25", "%26", "%27",
+    "%28", "%29", "%2a", "%2b", "%2c", "%2d", "%2e", "%2f",
+    "%30", "%31", "%32", "%33", "%34", "%35", "%36", "%37",
+    "%38", "%39", "%3a", "%3b", "%3c", "%3d", "%3e", "%3f",
+    "%40", "%41", "%42", "%43", "%44", "%45", "%46", "%47",
+    "%48", "%49", "%4a", "%4b", "%4c", "%4d", "%4e", "%4f",
+    "%50", "%51", "%52", "%53", "%54", "%55", "%56", "%57",
+    "%58", "%59", "%5a", "%5b", "%5c", "%5d", "%5e", "%5f",
+    "%60", "%61", "%62", "%63", "%64", "%65", "%66", "%67",
+    "%68", "%69", "%6a", "%6b", "%6c", "%6d", "%6e", "%6f",
+    "%70", "%71", "%72", "%73", "%74", "%75", "%76", "%77",
+    "%78", "%79", "%7a", "%7b", "%7c", "%7d", "%7e", "%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"
+  };
+
+  /**
+   * Encode a string to the "x-www-form-urlencoded" form, enhanced
+   * with the UTF-8-in-URL proposal. This is what happens:
+   *
+   * <ul>
+   * <li><p>The ASCII characters 'a' through 'z', 'A' through 'Z',
+   *        and '0' through '9' remain the same.
+   *
+   * <li><p>The space character ' ' is converted into a plus sign '+'.
+   *
+   * <li><p>All other ASCII characters are converted into the
+   *        3-character string "%xy", where xy is
+   *        the two-digit hexadecimal representation of the character
+   *        code
+   *
+   * <li><p>All non-ASCII characters are encoded in two steps: first
+   *        to a sequence of 2 or 3 bytes, using the UTF-8 algorithm;
+   *        secondly each of these bytes is encoded as "%xx".
+   * </ul>
+   *
+   * @param s The string to be encoded
+   * @return The encoded string
+   */
+  public static String encode(String s)
+  {
+    StringBuffer sbuf = new StringBuffer();
+    int len = s.length();
+    for (int i = 0; i < len; i++) {
+      int ch = s.charAt(i);
+      if ('A' <= ch && ch <= 'Z') {		// 'A'..'Z'
+	sbuf.append((char)ch);
+      } else if ('a' <= ch && ch <= 'z') {	// 'a'..'z'
+	sbuf.append((char)ch);
+      } else if ('0' <= ch && ch <= '9') {	// '0'..'9'
+	sbuf.append((char)ch);
+      } else if (ch == ' ') {			// space
+	sbuf.append('+');
+      } else if (ch <= 0x007f) {		// other ASCII
+	sbuf.append(hex[ch]);
+      } else if (ch <= 0x07FF) {		// non-ASCII <= 0x7FF
+	sbuf.append(hex[0xc0 | (ch >> 6)]);
+	sbuf.append(hex[0x80 | (ch & 0x3F)]);
+      } else {					// 0x7FF < ch <= 0xFFFF
+	sbuf.append(hex[0xe0 | (ch >> 12)]);
+	sbuf.append(hex[0x80 | ((ch >> 6) & 0x3F)]);
+	sbuf.append(hex[0x80 | (ch & 0x3F)]);
+      }
+    }
+    return sbuf.toString();
+  }
+
+}
+
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/Library1.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/Library1.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/Library1.java	(revision 14125)
@@ -0,0 +1,69 @@
+/*
+ *    Library1.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3;
+
+import org.greenstone.gsdl3.core.*;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+/** sample command line interface to gsdl3 site
+ *
+ * enter XML queries at the prompt
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @version $Revision$
+ */
+final public class Library1 {
+
+    public static void main(String args[]) {
+
+	if (args.length != 1) {
+	    System.out.println("Usage: Library1 <sitename>");
+	    System.exit(1);
+	}
+	String site_name = args[0];
+
+	MessageRouter mr = new MessageRouter();
+	mr.setSiteName(site_name);
+	mr.configure();
+	
+	BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+	String query=null;
+	String result=null;
+	while (true) {
+	    System.out.println("Please enter an XML query all on one line, or 'exit' to quit");
+	    try {
+		query = br.readLine();
+	    } catch (Exception e) {
+		System.err.println("Library1 exception:"+e.getMessage());
+	    }
+	    if (query.startsWith("exit")) {
+		System.exit(1);
+	    }
+	    System.out.println("\nProcessing query");
+	    
+	    result = mr.process(query);
+
+	    System.out.println("Result:\n"+result+"\n");
+
+
+	}
+       
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/Library2.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/Library2.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/Library2.java	(revision 14125)
@@ -0,0 +1,183 @@
+/*
+ *    Library2.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3;
+
+import org.greenstone.gsdl3.core.*;
+import org.greenstone.gsdl3.util.*;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.Iterator;
+/**
+ * A program to take cgi args from the command line and return html
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @version $Revision$
+ */
+
+final public class Library2 {
+ 
+    protected XMLConverter converter = null;
+    protected Document doc = null;
+    
+    protected HashMap saved_args = null;
+    protected GSParams params = null;
+    protected DefaultReceptionist recept = null;
+    
+    public Library2 (){
+	this.converter = new XMLConverter();
+	this.doc = converter.newDOM();
+	this.saved_args = new HashMap();
+	this.params = new GSParams();
+	this.recept = new DefaultReceptionist();
+    }
+    
+    public void configure(String site_name, String interface_name) {
+
+	HashMap config_params = new HashMap();
+	//config_params.put(GSConstants.GSDL3_HOME, gsdl_home);
+	config_params.put(GSConstants.SITE_NAME, site_name);
+	config_params.put(GSConstants.INTERFACE_NAME, interface_name);
+	// new message router - create it and pass a handle to recept.
+	// the servlet wont use this directly
+	MessageRouter message_router = new MessageRouter();
+	
+	message_router.setSiteName(site_name);
+	message_router.configure();
+	// new receptionist
+	recept.setConfigParams(config_params);
+	recept.setMessageRouter(message_router);
+	recept.setParams(params);
+	recept.configure();
+    }
+    public static void main(String args[]) {
+
+	if (args.length != 2) {
+	    System.out.println("Usage: Library2 <site name> <interface name>");
+	    System.exit(1);
+	}
+	
+	Library2 library = new Library2();
+	library.configure(args[0], args[1]);
+	
+
+	BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+	String query=null;
+	String result=null;
+	while (true) {
+	    System.out.println("Please enter the  cgi args (all on one line), or 'exit' to quit (default a=p&sa=home)");
+	    try {
+		query = br.readLine();
+	    } catch (Exception e) {
+		System.err.println("Library2 exception:"+e.getMessage());
+	    }
+	    if (query.startsWith("exit")) {
+		System.exit(1);
+	    }
+
+	    result = library.process(query);
+	    
+	    System.out.println(result);
+
+
+	}
+
+    } 
+
+    protected String process(String query) {
+	Element xml_message  = generateRequest(query);
+	System.out.println("*********************");
+	System.out.println(converter.getPrettyString(xml_message));
+	Element xml_result = recept.process(xml_message);
+	return this.converter.getPrettyString(xml_result);
+    }
+    protected Element generateRequest(String cgiargs) {
+
+	Element xml_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element xml_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PAGE, "", "", "");
+	xml_message.appendChild(xml_request);
+	Element xml_param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	xml_request.appendChild(xml_param_list);
+
+	// the defaults
+	String action = "p";
+	String subaction = "home";
+	String lang = (String)saved_args.get(GSParams.LANGUAGE);
+	if (lang == null) {
+	    lang = "en";
+	}
+	String output = "html";
+	
+	String args [] = cgiargs.split("&");
+	for (int i=0; i<args.length; i++) {
+	    String arg = args[i];
+	    int pos = arg.indexOf('=');
+	    if (pos == -1) continue;
+	    String name = arg.substring(0, pos);
+	    String value = arg.substring(pos+1);
+	    if (name.equals(GSParams.ACTION)) {
+		action = value;
+	    } else if (name.equals(GSParams.SUBACTION)) {
+		subaction = (value);
+	    } else if (name.equals(GSParams.LANGUAGE)) {
+		lang = value;
+		saved_args.put(name, value);
+	    } else if (name.equals(GSParams.OUTPUT)) {
+		output = value;
+	    } else if (params.shouldSave(name)) {
+		saved_args.put(name, value);
+	    } else {
+		// make a param now
+		Element param = doc.createElement(GSXML.PARAM_ELEM);
+		param.setAttribute(GSXML.NAME_ATT, name);
+		param.setAttribute(GSXML.VALUE_ATT, GSXML.xmlSafe(value));
+		xml_param_list.appendChild(param);
+	    }
+	}
+
+	xml_request.setAttribute(GSXML.OUTPUT_ATT, output);
+	xml_request.setAttribute(GSXML.ACTION_ATT, action);
+	xml_request.setAttribute(GSXML.SUBACTION_ATT, subaction);
+	xml_request.setAttribute(GSXML.LANG_ATT, lang);
+
+
+	// put in all the params from the session cache
+	Set params = saved_args.keySet();
+	Iterator i = params.iterator();
+	while (i.hasNext()) {
+	    String name = (String)i.next();
+	    if (name.equals(GSParams.LANGUAGE)) continue;
+	    Element param = this.doc.createElement(GSXML.PARAM_ELEM);
+	    param.setAttribute(GSXML.NAME_ATT, name);
+	    param.setAttribute(GSXML.VALUE_ATT, GSXML.xmlSafe((String)saved_args.get(name)));
+	    xml_param_list.appendChild(param);
+	}
+
+	return xml_message;
+    }
+}
+
+    
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/LibraryServlet.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/LibraryServlet.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/LibraryServlet.java	(revision 14125)
@@ -0,0 +1,375 @@
+package org.greenstone.gsdl3;
+
+import org.greenstone.gsdl3.comms.*;
+import org.greenstone.gsdl3.core.*;
+import org.greenstone.gsdl3.util.*;
+import org.greenstone.gsdl3.action.PageAction; // used to get the default action
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.io.File;
+
+import org.apache.log4j.*;
+
+/** a servlet to serve the greenstone library - we are using servlets instead
+ * of cgi
+ * the init method is called only once - the first time the servlet classes
+ * are loaded. Each time a request comes in to the servlet, the session()
+ * method is called in a new thread (calls doGet/doPut etc)
+ * takes the a=p&p=home type args and builds a simple request to send to 
+ * its receptionist, which returns a result in html, cos output=html
+ * is set in the request
+ * @see Receptionist
+ */
+public class LibraryServlet extends HttpServlet {
+    
+    /** the receptionist to send messages to */
+    protected Receptionist recept=null;
+    /** the default language - is specified by setting a servlet param,
+     * otherwise DEFAULT_LANG is used*/
+    protected String default_lang= null;
+    /** The default default - used if a default lang is not specified 
+     * in the servlet params */
+    protected final String DEFAULT_LANG = "en";
+    /** container Document to create XML Nodes */
+    protected Document doc=null;    
+    /** a converter class to parse XML and create Docs */
+    protected XMLConverter converter=null;
+    /** the cgi stuff - the Receptionist can add new args to this
+     * its used by the servlet to determine what args to save */
+    protected GSParams params = null;
+
+    /** user id - new one per session. This doesn't work if session state is saved between restarts - this requires this value to be saved too. */
+    protected int next_user_id = 0;
+
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.LibraryServlet.class.getName());
+
+    /** initialise the servlet
+     */
+    public void init(ServletConfig config) throws ServletException {
+	// always call super.init;
+	super.init(config);
+	// disable preferences - does this work anyway??
+	//System.setProperty("java.util.prefs.PreferencesFactory", "org.greenstone.gsdl3.util.DisabledPreferencesFactory");
+
+    
+	String library_name = config.getInitParameter(GSConstants.LIBRARY_NAME);
+	String gsdl3_home = config.getInitParameter(GSConstants.GSDL3_HOME);
+	String interface_name = config.getInitParameter(GSConstants.INTERFACE_NAME);
+	this.default_lang = config.getInitParameter(GSConstants.DEFAULT_LANG);
+
+	if (library_name == null || interface_name ==null) {
+	    // must have this
+	    System.err.println("initialisation parameters not all set!");
+	    System.err.println(" you must have libraryname and interfacename");
+	    System.exit(1);
+	}
+
+	String site_name = config.getInitParameter(GSConstants.SITE_NAME);
+	String remote_site_name = null;
+	String remote_site_type = null;
+	String remote_site_address = null;
+	
+	if (site_name == null) {
+	    // no site, try for communicator
+	    remote_site_name = config.getInitParameter("remote_site_name");
+	    remote_site_type = config.getInitParameter("remote_site_type");
+	    remote_site_address = config.getInitParameter("remote_site_address");
+	    if (remote_site_name == null || remote_site_type == null || remote_site_address == null) {
+		System.err.println("initialisation paramters not all set!");
+		System.err.println("if site_name is not set, then you must have remote_site_name, remote_site_type and remote_site_address set");
+		System.exit(1); 
+	    }
+	}
+	
+	if (this.default_lang == null) {
+	    // choose english
+	    this.default_lang = DEFAULT_LANG;
+	}
+	
+	HashMap config_params = new HashMap();
+	
+	config_params.put(GSConstants.LIBRARY_NAME, library_name);
+	config_params.put(GSConstants.INTERFACE_NAME, interface_name);
+	if (site_name != null) {
+	    config_params.put(GSConstants.SITE_NAME, site_name);
+	}
+	this.converter = new XMLConverter();
+	this.doc = this.converter.newDOM();
+	
+	// the receptionist -the servlet will talk to this
+	String recept_name = (String)config.getInitParameter("receptionist_class");
+	if (recept_name == null) {
+	    this.recept = new DefaultReceptionist();
+	} else {
+	    try {
+		this.recept = (Receptionist)Class.forName("org.greenstone.gsdl3.core."+recept_name).newInstance();
+	    } catch (Exception e) { // cant use this new one, so use normal one
+		System.err.println("LibraryServlet configure exception when trying to use a new Receptionist "+recept_name+": "+e.getMessage());
+		e.printStackTrace();
+		this.recept = new DefaultReceptionist();
+	    }
+	}
+	this.recept.setConfigParams(config_params);
+
+	// the receptionist uses a MessageRouter or Communicator to send its requests to. We either create a MessageRouter here for the designated site (if site_name set), or we create a Communicator for a remote site. The is given to teh Receptionist, and the servlet never talks to it again.directly.
+	if (site_name != null) {
+	    String mr_name = (String)config.getInitParameter("messagerouter_class");
+	    MessageRouter message_router = null;
+	    if (mr_name == null) { // just use the normal MR
+		message_router = new MessageRouter();
+	    } else { // try the specified one
+		try {
+		    message_router = (MessageRouter)Class.forName("org.greenstone.gsdl3.core."+mr_name).newInstance();
+		} catch (Exception e) { // cant use this new one, so use normal one
+		    System.err.println("LibraryServlet configure exception when trying to use a new MessageRouter "+mr_name+": "+e.getMessage());
+		    e.printStackTrace();
+		    message_router = new MessageRouter();
+		}   
+	    }
+	    
+	    message_router.setSiteName(site_name);
+	    message_router.configure();
+	    this.recept.setMessageRouter(message_router);
+	} else {
+	    // talking to a remote site, create a communicator
+	    Communicator communicator = null;
+	    // we need to create the XML to configure the communicator
+	    Element site_elem = this.doc.createElement(GSXML.SITE_ELEM);
+	    site_elem.setAttribute(GSXML.TYPE_ATT, remote_site_type);
+	    site_elem.setAttribute(GSXML.NAME_ATT, remote_site_name);
+	    site_elem.setAttribute(GSXML.ADDRESS_ATT, remote_site_address);
+
+	    if (remote_site_type.equals(GSXML.COMM_TYPE_SOAP_JAVA)) {
+		communicator = new SOAPCommunicator();
+	    } else {
+		System.err.println("LibraryServlet.init Error: invalid Communicator type: "+remote_site_type);
+		System.exit(1);
+	    }
+	    
+	    if (!communicator.configure(site_elem)) {
+		System.err.println("LibraryServlet.init Error: Couldn't configure communicator");
+		System.exit(1);
+	    }
+	    this.recept.setMessageRouter(communicator);
+	}
+	
+	// the params arg thingy
+	
+	String params_name = (String)config.getInitParameter("params_class");
+	if (params_name == null) {
+	    this.params = new GSParams();
+	} else {
+	    try {
+		this.params = (GSParams)Class.forName("org.greenstone.gsdl3.util."+params_name).newInstance();
+	    } catch (Exception e) {
+		System.err.println("LibraryServlet configure exception when trying to use a new params thing "+params_name+": "+e.getMessage());
+		e.printStackTrace();
+		this.params = new GSParams();
+	    }
+	}
+	// pass it to the receptionist
+	this.recept.setParams(this.params);
+	this.recept.configure();
+	
+    }
+
+
+    private void logUsageInfo(HttpServletRequest request){
+	String usageInfo = "";
+
+	//session-info: get params stored in the session
+	HttpSession session = request.getSession(true);
+        Enumeration attributeNames = session.getAttributeNames();
+	while(attributeNames.hasMoreElements()) {
+	    String name = (String)attributeNames.nextElement();
+	    usageInfo +=name+"="+session.getAttribute(name)+" ";
+	}
+	
+	//logged info = general-info + session-info
+	usageInfo = 
+	    request.getServletPath()+" "+ //serlvet
+	    "["+request.getQueryString()+"]" +" "+ //the query string
+	    "["+usageInfo.trim()+"]" +" "+ // params stored in a session
+	    request.getRemoteAddr()+" "+   //remote address                  
+	    request.getRequestedSessionId()+" "+ //session id
+	    request.getHeader("user-agent")+" "; //the remote brower info                      
+                         
+	logger.info(usageInfo);
+
+    }
+
+       
+    public void doGet(HttpServletRequest request,
+		      HttpServletResponse response)
+	throws ServletException, IOException {
+
+	logUsageInfo(request);
+          
+	// Nested Diagnostic Configurator to identify the client for
+       
+	HttpSession session = request.getSession(true);
+        String uid = (String)session.getAttribute(GSXML.USER_ID_ATT);
+	if (uid ==null) {
+	    uid = ""+getNextUserId();
+	    session.setAttribute(GSXML.USER_ID_ATT, uid);
+	}
+	request.setCharacterEncoding("UTF-8");
+	response.setContentType("text/html;charset=UTF-8");
+	PrintWriter out = response.getWriter();
+
+	String lang = request.getParameter(GSParams.LANGUAGE);
+	if (lang==null || lang.equals("")) {
+	    // try the session cached lang
+	    lang = (String)session.getAttribute(GSParams.LANGUAGE);
+	    if (lang==null || lang.equals("")) {
+		// still not set, use the default
+		lang = this.default_lang;
+	    }
+	}
+	
+	// set the lang in the session
+	session.setAttribute(GSParams.LANGUAGE, lang);
+
+	String output = request.getParameter(GSParams.OUTPUT);
+	if (output==null || output.equals("")) {
+	    output = "html"; // uses html by default
+	}
+
+	// the request to the receptionist	
+	Element xml_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element xml_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PAGE, "", lang, uid);
+	xml_request.setAttribute(GSXML.OUTPUT_ATT, output);
+	xml_message.appendChild(xml_request);
+	
+	
+	String action = request.getParameter(GSParams.ACTION);
+	String subaction = request.getParameter(GSParams.SUBACTION);
+	if (action==null || action.equals("")) {
+	    // should we do all the following stuff if using default page?
+	    // display the home page  - the default page
+	    action = "p";
+	    subaction = PageAction.HOME_PAGE;
+	    xml_request.setAttribute(GSXML.ACTION_ATT, action);
+	    xml_request.setAttribute(GSXML.SUBACTION_ATT, subaction);
+	    
+	} else {
+	
+	    xml_request.setAttribute(GSXML.ACTION_ATT, action);
+	    if (subaction != null) {
+		xml_request.setAttribute(GSXML.SUBACTION_ATT, subaction);
+	    }
+
+	    //  create the param list for the greenstone request - includes
+	    // the params from the current request and any others from the saved session
+	    Element xml_param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	    xml_request.appendChild(xml_param_list);
+	    
+	    Enumeration params = request.getParameterNames();
+	    while(params.hasMoreElements()) {
+		String name = (String)params.nextElement();
+		if (!name.equals(GSParams.ACTION) && !name.equals(GSParams.SUBACTION) && !name.equals(GSParams.LANGUAGE) && !name.equals(GSParams.OUTPUT)) {// we have already dealt with these 
+		    String value="";
+		    String [] values = request.getParameterValues(name);
+		    value = values[0];
+		    if (values.length > 1) {
+			for (int i=1; i< values.length; i++) {
+			    value += ","+values[i];
+			}
+		    }
+		    // either add it to the param list straight away, or save it to the session and add it later
+		    if (this.params.shouldSave(name)) {			
+			session.setAttribute(name, value);
+		    } else { 
+			Element param = this.doc.createElement(GSXML.PARAM_ELEM);
+			param.setAttribute(GSXML.NAME_ATT, name);
+			param.setAttribute(GSXML.VALUE_ATT, GSXML.xmlSafe(value));
+			xml_param_list.appendChild(param);
+		    }
+		}
+	    }
+	    
+	    // put in all the params from the session cache
+	    params = session.getAttributeNames();
+	    while(params.hasMoreElements()) {
+		String name = (String)params.nextElement();
+		
+		if ( !name.equals(GSParams.LANGUAGE) && !name.equals(GSXML.USER_ID_ATT)) { // lang and uid are stored but we dont want it in the param list cos its already in the request
+		    
+		    Element param = this.doc.createElement(GSXML.PARAM_ELEM);
+		    param.setAttribute(GSXML.NAME_ATT, name);
+		    String value =  GSXML.xmlSafe((String)session.getAttribute(name));
+		    // ugly hack to undo : escaping
+		    value = value.replaceAll("%3A", "\\:");
+		    param.setAttribute(GSXML.VALUE_ATT,value);
+		    xml_param_list.appendChild(param);
+		}
+	    }
+
+	
+	}
+	
+	if (!output.equals("html")) {
+	    response.setContentType("text/xml"); // for now use text
+	}
+
+	//GSXML.printXMLNode(xml_message);	
+
+	Element xml_result = this.recept.process(xml_message);
+	encodeURLs(xml_result, response);
+	out.println(this.converter.getPrettyString(xml_result));
+    }
+
+    /** this goes through each URL and adds in a session id if needed--
+     * its needed if the browser doesn't accept cookies
+     * also escapes things if needed
+     */
+    protected void encodeURLs(Element data, HttpServletResponse response) {
+	
+	if (data == null) {
+	    return;
+	}
+	// get all the <a> elements
+	NodeList hrefs = data.getElementsByTagName("a");
+	for (int i=0; i<hrefs.getLength(); i++) {
+	    Element a = (Element)hrefs.item(i);
+	    // ugly hack to get rid of : in the args - interferes with session handling
+	    String href = a.getAttribute("href");
+	    if (!href.equals("")) {
+		if (href.indexOf("?")!=-1) {
+		    String[] parts = href.split("\\?", -1);
+		    parts[1]=parts[1].replaceAll(":", "%3A");
+		    href = parts[0]+"?"+parts[1];
+		}
+		a.setAttribute("href", response.encodeURL(href));
+	    }
+	}
+	
+	// now find any submit bits - get all the <form> elements
+	NodeList forms = data.getElementsByTagName("form");
+	for (int i=0; i<forms.getLength(); i++) {
+	    Element form = (Element)forms.item(i);
+	    form.setAttribute("action", response.encodeURL(form.getAttribute("action")));
+	}
+	// are these the only cases where URLs occur??
+	// we should only do this for greenstone urls?
+	
+    }
+
+    synchronized protected int getNextUserId() {
+	next_user_id++;
+	return next_user_id;
+    }
+
+    public void doPost(HttpServletRequest request,
+		      HttpServletResponse response)
+	throws ServletException, IOException {
+	doGet(request,response);
+
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/SOAPServerlocalsite.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/SOAPServerlocalsite.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/SOAPServerlocalsite.java	(revision 14125)
@@ -0,0 +1,87 @@
+/*
+ *    SOAPServer.java.in: a template for a new SOAPServer
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3;
+
+import org.greenstone.gsdl3.core.MessageRouter;
+import org.greenstone.gsdl3.util.GlobalProperties;
+import org.greenstone.gsdl3.util.GSFile;
+import org.greenstone.gsdl3.util.GSXML;
+import org.w3c.dom.Element;
+import java.io.File;
+
+/**
+ * The server side of a SOAP connection
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @see <a href="http://www.w3.org/TR/SOAP/">Simple Object Access Protocol (SOAP) 1.1 </a>
+ */
+
+public class SOAPServerlocalsite
+{
+    
+    /** The message router we're talking to */
+    protected MessageRouter mr=null;
+    /** the name of the site we are serving */
+    protected String site_name = "localsite";
+  
+    /** The no-args constructor */
+    public SOAPServerlocalsite() {
+	String gsdl3_home = GlobalProperties.getGSDL3Home();
+	if (gsdl3_home == null || gsdl3_home.equals("")) {
+	    System.err.println("Couldn't access GSDL3Home from GlobalProerties.getGSDL3HOME, can't initialize the SOAP Server.");
+	    return;
+	}
+	String site_home = GSFile.siteHome(gsdl3_home, this.site_name);
+	
+	File site_file = new File(site_home);
+	if (!site_file.isDirectory()) {
+	    System.err.println("The site directory "+site_file.getPath()+" doesn't exist. Can't initialize the SOAP Server.");
+	    return;
+	}   	
+	mr = new MessageRouter();
+	mr.setSiteName(this.site_name);
+	mr.configure();
+    }
+    
+    
+    public Element [] process (Element [] xml_in) {
+	Element [] result = new Element[xml_in.length];
+	for (int i=0; i<xml_in.length; i++) {
+	    Element req = xml_in[i];
+	    // get rid of the obligatory namespace that axis needs
+	    String tag_name = req.getTagName();
+	    String namespace="";
+	    if (tag_name.indexOf(':')!= -1) {
+		namespace = tag_name.substring(0, tag_name.indexOf(':'));
+		tag_name = tag_name.substring(tag_name.indexOf(':')+1);	
+	    }
+	    Element new_req = GSXML.duplicateWithNewName(req.getOwnerDocument(), req, tag_name, true);
+	    Element r = mr.process(new_req);
+	    // add the namespace back on
+	    //Element new_res = r;
+	    //if (!namespace.equals("")) {
+	    //	new_res = GSXML.duplicateWithNewName(r.getOwnerDocument(), r, namespace+r.getTagName(), true);
+	    //}
+	    result[i] = r;
+	}
+	return result;
+    }   
+}
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/Action.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/Action.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/Action.java	(revision 14125)
@@ -0,0 +1,140 @@
+package org.greenstone.gsdl3.action;
+
+import org.greenstone.gsdl3.core.ModuleInterface;
+import org.greenstone.gsdl3.util.*;
+// XML classes
+import org.w3c.dom.Node; 
+import org.w3c.dom.NodeList; 
+import org.w3c.dom.Element; 
+import org.w3c.dom.Document; 
+
+// other java stuff
+import java.io.File;
+import java.util.Vector;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import org.apache.log4j.*;
+
+/** base class for Actions */
+abstract public class Action {
+
+    /** the system set up variables */
+    protected HashMap config_params = null;
+    /** container Document to create XML Nodes */
+    protected Document doc=null; 
+    /** a converter class to parse XML and create Docs */
+    protected XMLConverter converter=null;
+    /** a reference to the message router that it must talk to to
+     * get info. it may be a communicator acting as a proxy, but it 
+     doesn't care about that */
+    protected ModuleInterface mr=null;
+
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.action.Action.class.getName());
+
+    public Action() {
+	this.converter = new XMLConverter();
+	this.doc = this.converter.newDOM();
+    }
+    /** the config variables must be set before configure is called */
+    public void setConfigParams(HashMap params) {
+	this.config_params = params;
+    }
+    /** sets the message router */
+    public void setMessageRouter(ModuleInterface m) {
+       this.mr = m;
+    }
+    public boolean configure() {
+	// does nothing yet
+	return true;
+    }
+    
+    /** process takes an xml representation of cgi args
+     * and returns the page of results - may be in html/xml/other
+     * depending on the output att of the request */
+    public String process(String xml_in) {
+       
+	Document message_doc = this.converter.getDOM(xml_in);
+	if (message_doc == null) {
+	    logger.error("Couldn't parse request");
+	    logger.error(xml_in);
+	    return null;
+	}
+	Element result = process(message_doc.getDocumentElement());
+	return this.converter.getString(result);
+    }
+    
+    /** the main process method - must be implemented in subclass */
+    abstract public Element process(Element xml_in);
+
+    /** tell the param class what its arguments are 
+     * if an action has its own arguments, this should add them to the params
+     * object - particularly important for args that should not be saved */
+    public boolean getActionParameters(GSParams params) {
+	return true;
+    }
+
+    protected void extractMetadataNames(Element format, HashSet meta_names) {
+	//NodeList nodes = format.getElementsByTagNameNS("metadata", "http://www.greenstone.org/configformat");
+	NodeList nodes = format.getElementsByTagName("gsf:metadata");
+        for (int i=0; i<nodes.getLength(); i++) {
+	    Element elem = (Element)nodes.item(i);
+	    StringBuffer metadata = new StringBuffer();
+	    String all = elem.getAttribute("multiple");
+	    String name = elem.getAttribute("name");
+	    String select = elem.getAttribute("select");
+	    String sep = elem.getAttribute("separator");
+	    if (all.equals("true")) {
+		metadata.append("all");
+		metadata.append(GSConstants.META_RELATION_SEP);
+	    }
+	    if (!select.equals("")) {
+		metadata.append(select);
+		metadata.append(GSConstants.META_RELATION_SEP);
+	    }
+	    if (!sep.equals("")) {
+		metadata.append(GSConstants.META_SEPARATOR_SEP);
+		metadata.append(sep);
+		metadata.append(GSConstants.META_SEPARATOR_SEP);
+		metadata.append(GSConstants.META_RELATION_SEP);
+	    }
+
+	    metadata.append(name);
+	    meta_names.add(metadata.toString());
+	}
+		
+    }
+
+    protected Element createMetadataParamList(HashSet metadata_names) {
+	Element param_list  = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	
+	Element param = null;
+	Iterator i = metadata_names.iterator();
+	while (i.hasNext()) {
+	    String name = (String)i.next();
+	    param = this.doc.createElement(GSXML.PARAM_ELEM);
+	    param_list.appendChild(param);
+	    param.setAttribute(GSXML.NAME_ATT, "metadata");
+	    param.setAttribute(GSXML.VALUE_ATT, name);
+	
+	}
+	return param_list;
+    }
+
+    protected boolean processErrorElements(Element message, Element page) {
+	NodeList error_nodes = message.getElementsByTagName(GSXML.ERROR_ELEM);
+	if (error_nodes.getLength()==0) {
+	    return false;
+	}
+	Document owner = page.getOwnerDocument();
+	for (int i=0; i<error_nodes.getLength(); i++) {
+	    page.appendChild(owner.importNode(error_nodes.item(i), true));
+	}
+	return true;
+    }
+}
+
+
+
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/AppletAction.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/AppletAction.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/AppletAction.java	(revision 14125)
@@ -0,0 +1,124 @@
+package org.greenstone.gsdl3.action;
+
+import org.greenstone.gsdl3.core.ModuleInterface;
+import org.greenstone.gsdl3.util.*;
+// XML classes
+import org.w3c.dom.Node; 
+import org.w3c.dom.NodeList; 
+import org.w3c.dom.Document; 
+import org.w3c.dom.Element; 
+
+import java.util.HashMap;
+import java.io.File;
+
+import org.apache.log4j.*;
+
+/** action class for handling applets */
+public class AppletAction extends Action {
+
+      static Logger logger = Logger.getLogger(org.greenstone.gsdl3.action.AppletAction.class.getName());   
+
+    public Element process (Element message) {
+	
+	Element request = (Element)GSXML.getChildByTagName(message, GSXML.REQUEST_ELEM);
+	Element result = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element page_response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.appendChild(page_response);
+
+	// get the collection and service params
+	Element cgi_param_list = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	HashMap params = GSXML.extractParams(cgi_param_list, false);
+
+	// request_type is display (d) or request (r)
+	String request_type = (String)params.get(GSParams.REQUEST_TYPE);
+	if (!request_type.equals("d")&&!request_type.equals("r")) {
+	    logger.error("AppletAction Error: the rt arg should be either d or r, instead it was "+request_type+"!");
+	    return result;
+	}
+	
+	String collection = (String)params.get(GSParams.COLLECTION);
+	boolean coll_specified = true;
+	String service_name=(String)params.get(GSParams.SERVICE);
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	String uid = request.getAttribute(GSXML.USER_ID_ATT);
+	String to=null;
+	if (collection==null||collection.equals("") ) {
+	    coll_specified = false;
+	    to = service_name;
+	} else {
+	    to = GSPath.appendLink(collection, service_name);
+	}
+
+	if (request_type.equals("r")) {
+	    // we are processing stuff for the applet send a message to the service, type="query", and take out the something element, and return that as our result - the applet must take xml
+
+	    Element mr_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	    Element mr_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, lang, uid); 
+	    mr_message.appendChild(mr_request);
+	    // just append all the params for now - should filter out unneeded ones
+	    mr_request.appendChild(this.doc.importNode(cgi_param_list, true));
+       
+	    // process the request
+	    Element mr_response = (Element)this.mr.process(mr_message);
+	    // get the applet data out and pass it back as is. 
+	    String path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.APPLET_DATA_ELEM);
+	    Element applet_info = (Element)GSXML.getNodeByPath(mr_response, path).getFirstChild();
+	    return applet_info;
+	    
+	}
+	
+
+	// get the applet description, and the collection info if a collection is specified
+	
+	Element mr_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element applet_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, to, lang, uid); 
+	mr_message.appendChild(applet_request);
+
+	
+	Element mr_response = (Element)this.mr.process(mr_message);
+
+	// add in the applet info
+	String path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.SERVICE_ELEM);
+	//path = GSPath.appendLink(path, GSXML.APPLET_ELEM);
+	Element service_elem = (Element)this.doc.importNode(GSXML.getNodeByPath(mr_response, path), true);
+	Element applet_elem = (Element)GSXML.getChildByTagName(service_elem, GSXML.APPLET_ELEM);
+	// must handle any params that have values that are not 
+	// necessarily known by the service
+	// should this be done here or by web receptionist??
+	// cant really have an applet without web?
+	editLocalParams(applet_elem, (String)config_params.get(GSConstants.LIBRARY_NAME), collection);
+	page_response.appendChild(service_elem);
+	
+	return result;
+	
+    }
+
+    /** this method looks through the PARAMs of the applet description for 
+     * 'library' or 'collection'. If found, the params are set to  
+     * the appropriate values 
+     * should this be done here or in the receptionist? 
+     */
+    protected void editLocalParams(Element description, String library_name,
+				   String full_collection_name) {
+
+	Node child = description.getFirstChild();
+	while (child != null) {
+	    if (child.getNodeType() == Node.ELEMENT_NODE) {
+		String param = child.getNodeName();
+		if (param.equals("PARAM")||param.equals("param")) {
+		    String name = ((Element)child).getAttribute("NAME");
+		    if (name == null || name.equals("")) {
+			// somethings wrong!!
+		    } else if (name.equals("library")) {
+			((Element)child).setAttribute("VALUE", library_name);
+		    } else if (name.equals("collection")) {
+			((Element)child).setAttribute("VALUE", full_collection_name);
+		    }
+		    
+		}
+	    }
+	    child = child.getNextSibling();
+	}
+    }
+	
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/BrowseAction.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/BrowseAction.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/BrowseAction.java	(revision 14125)
@@ -0,0 +1,297 @@
+package org.greenstone.gsdl3.action;
+
+import org.greenstone.gsdl3.core.ModuleInterface;
+import org.greenstone.gsdl3.util.*;
+// XML classes
+import org.w3c.dom.Node; 
+import org.w3c.dom.NodeList; 
+import org.w3c.dom.Document; 
+import org.w3c.dom.Element; 
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Vector;
+import java.io.File;
+
+import org.apache.log4j.*;
+
+//NOTE: this class not used at present!!!!!
+/** action for classifier browsing */
+public class BrowseAction extends Action {
+
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.action.BrowseAction.class.getName());
+
+    public static final String CLASSIFIER_ARG = "cl";
+    public static final String SIBLING_ARG = "sib";
+
+    /** process the request */
+    public Element process (Element message) {
+
+	// get the request - assume only one
+	Element request = (Element)GSXML.getChildByTagName(message, GSXML.REQUEST_ELEM);
+
+	// the result
+	Element result = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element response = classifierBrowse(request);
+	result.appendChild(response);
+	return result;
+    }
+    
+
+    protected Element classifierBrowse(Element request) {
+
+	Element page_response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+
+	// extract the params from the cgi-request, and check that we have a coll specified
+	Element cgi_paramList = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	HashMap params = GSXML.extractParams(cgi_paramList, false);
+
+	String service_name = (String)params.get(GSParams.SERVICE);
+	String collection = (String)params.get(GSParams.COLLECTION);
+	if (collection == null || collection.equals("")) {
+	    logger.error("classifierBrowse, need to specify a collection!");
+	    return page_response;
+	   
+	}
+	
+	//whether to retrieve siblings or not
+	boolean get_siblings = false;
+	String sibs = (String) params.get(SIBLING_ARG);
+	if (sibs != null && sibs.equals("1")) {
+	    get_siblings = true;
+	}
+
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	String uid = request.getAttribute(GSXML.USER_ID_ATT);	
+	String to = GSPath.appendLink(collection, service_name);
+	
+	// the first part of the response is the service description 
+	// for now get this again from the service. 
+	// this should be cached somehow later on. 
+	
+	Element info_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element info_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, to, lang, uid); 
+	info_message.appendChild(info_request);
+	
+	// also get the format stuff now if there is some
+	Element format_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_FORMAT, to, lang, uid);
+	info_message.appendChild(format_request);
+	// process the requests
+
+	Element info_response = (Element) this.mr.process(info_message);
+
+	// the two responses
+	NodeList responses = info_response.getElementsByTagName(GSXML.RESPONSE_ELEM);
+	Element service_response = (Element)responses.item(0);
+	Element format_response = (Element)responses.item(1);
+
+	Element service_description = (Element)GSXML.getChildByTagName(service_response, GSXML.SERVICE_ELEM);
+	page_response.appendChild(this.doc.importNode(service_description, true));
+	
+	// if rt=d, then we are just displaying the service
+	String request_type = (String)params.get(GSParams.REQUEST_TYPE);
+	if (request_type.equals("d")) {
+	    //return the page that we have so far
+	    return page_response;
+	}
+    
+	// get the node that the user has clicked on
+	String classifier_node = (String)params.get(CLASSIFIER_ARG);
+	
+	// if the node is not defined, return the page that we have so far
+	if (classifier_node ==null || classifier_node.equals("")) {
+	    return page_response;
+	}
+	
+	// the id of the classifier is the top id of the selected node
+	String top_id = OID.getTop(classifier_node);
+	
+	HashSet metadata_names = new HashSet();
+
+	// add the format info into the response
+	Element format_elem = (Element)GSXML.getChildByTagName(format_response, GSXML.FORMAT_ELEM);
+	if (format_elem != null) {
+	    // find the one for the classifier we are in
+	    Element this_format = GSXML.getNamedElement(format_elem, GSXML.CLASSIFIER_ELEM, GSXML.NAME_ATT, top_id);
+	    if (this_format == null) {
+		this_format = (Element)GSXML.getChildByTagName(format_elem, GSXML.DEFAULT_ELEM);
+	    }
+	    if (this_format != null) {
+		Element new_format = GSXML.duplicateWithNewName(this.doc, this_format, GSXML.FORMAT_ELEM, false);
+		// set teh format type
+		new_format.setAttribute(GSXML.TYPE_ATT, "browse");
+
+		page_response.appendChild(new_format);
+		extractMetadataNames(new_format, metadata_names);
+	    }
+	}
+	
+	logger.info("extracted meta names, "+metadata_names.toString());
+	// get the browse structure for the selected node
+	Element classify_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element classify_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, lang, uid);
+	classify_message.appendChild(classify_request);
+	    
+	//Create a parameter list to specify the required structure information
+	// for now, always get ancestors and children
+	Element param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	classify_request.appendChild(param_list);
+	Element param = this.doc.createElement(GSXML.PARAM_ELEM);
+	param_list.appendChild(param);
+	param.setAttribute(GSXML.NAME_ATT, "structure");
+	param.setAttribute(GSXML.VALUE_ATT, "ancestors");
+	param = this.doc.createElement(GSXML.PARAM_ELEM);
+	param_list.appendChild(param);
+	param.setAttribute(GSXML.NAME_ATT, "structure");
+	param.setAttribute(GSXML.VALUE_ATT, "children");
+	if (get_siblings) {
+	    param = this.doc.createElement(GSXML.PARAM_ELEM);
+	    param_list.appendChild(param);
+	    param.setAttribute(GSXML.NAME_ATT, "structure");
+	    param.setAttribute(GSXML.VALUE_ATT, "siblings");
+	}
+
+	// put the classifier node into a classifier node list
+	Element classifier_list = this.doc.createElement(GSXML.CLASS_NODE_ELEM+GSXML.LIST_MODIFIER);
+	Element classifier = this.doc.createElement(GSXML.CLASS_NODE_ELEM);
+	classifier.setAttribute(GSXML.NODE_ID_ATT, classifier_node);
+	classifier_list.appendChild(classifier);
+	classify_request.appendChild(classifier_list);
+	    
+	// process the request
+	Element classify_response = (Element)this.mr.process(classify_message);
+	// get the structure element
+	String path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.CLASS_NODE_ELEM+GSXML.LIST_MODIFIER);
+	path = GSPath.appendLink(path, GSXML.CLASS_NODE_ELEM);
+	path = GSPath.appendLink(path, GSXML.NODE_STRUCTURE_ELEM);
+	// assume that we always get back the top level CL1 node - this becomes the page_classifier node
+	path = GSPath.appendLink(path, GSXML.CLASS_NODE_ELEM);
+	Element cl_structure = (Element)GSXML.getNodeByPath(classify_response,
+							    path);
+	if (cl_structure ==null) {
+	    logger.error("classifier structure request returned no structure");
+	    return page_response;
+	}   
+    
+	// add the classifier node as the page classifier 
+	Element page_classifier = GSXML.duplicateWithNewName(this.doc, cl_structure,  GSXML.CLASSIFIER_ELEM, true);
+	page_response.appendChild(page_classifier);
+	page_classifier.setAttribute(GSXML.NAME_ATT, top_id);
+	
+	// get the metadata for each classifier node, 
+	// then for each document node
+
+	Element metadata_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+
+	boolean did_classifier = false;
+	boolean did_documents = false;
+	
+    
+	// if there are classifier nodes 
+	// create a metadata request for the classifier, and add it to 
+	// the the message
+	NodeList cl_nodes = page_classifier.getElementsByTagName(GSXML.CLASS_NODE_ELEM);
+	
+	if (cl_nodes.getLength() > 0) {
+	    did_classifier = true;
+	    Element cl_meta_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to+"MetadataRetrieve", lang, uid);
+	    metadata_message.appendChild(cl_meta_request);
+	    
+	    Element new_cl_nodes_list = this.doc.createElement(GSXML.CLASS_NODE_ELEM+GSXML.LIST_MODIFIER);
+	    cl_meta_request.appendChild(new_cl_nodes_list);
+	    
+	    for (int c=0; c<cl_nodes.getLength(); c++) {
+
+		Element cl = this.doc.createElement(GSXML.CLASS_NODE_ELEM);
+		cl.setAttribute(GSXML.NODE_ID_ATT, ((Element)cl_nodes.item(c)).getAttribute(GSXML.NODE_ID_ATT));
+		new_cl_nodes_list.appendChild(cl);
+	    }
+
+	    // create and add in the param list - for now get all the metadata
+	    // should be based on info sent in from the recept, and the 
+	    // format stuff
+	    Element cl_param_list = null;
+	    if (metadata_names.isEmpty()) {
+		cl_param_list  = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+		Element p = this.doc.createElement(GSXML.PARAM_ELEM);
+		cl_param_list.appendChild(p);
+		p.setAttribute(GSXML.NAME_ATT, "metadata");
+		p.setAttribute(GSXML.VALUE_ATT, "Title");
+	    } else {
+		cl_param_list  = createMetadataParamList(metadata_names);
+	    }
+
+	    cl_meta_request.appendChild(cl_param_list);
+	    
+	}
+
+	// if there are document nodes in the classification (happens 
+	// sometimes), create a second request for document metadata and 
+	// append to the message
+	NodeList doc_nodes = page_classifier.getElementsByTagName(GSXML.DOC_NODE_ELEM);
+	if (doc_nodes.getLength() > 0) {
+	    did_documents = true;
+	    Element doc_meta_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, GSPath.appendLink(collection, "DocumentMetadataRetrieve"), lang, uid);
+	    metadata_message.appendChild(doc_meta_request);
+	    
+	    Element doc_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	    doc_meta_request.appendChild(doc_list);
+	    
+	    for (int c=0; c<doc_nodes.getLength(); c++) {
+		
+		Element d = this.doc.createElement(GSXML.DOC_NODE_ELEM);
+		d.setAttribute(GSXML.NODE_ID_ATT, ((Element)doc_nodes.item(c)).getAttribute(GSXML.NODE_ID_ATT));
+		doc_list.appendChild(d);
+	    }
+
+	    // create and add in the param list - add all for now
+	    Element doc_param_list  = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	    Element p = this.doc.createElement(GSXML.PARAM_ELEM);
+	    doc_param_list.appendChild(p);
+	    p.setAttribute(GSXML.NAME_ATT, "metadata");
+	    p.setAttribute(GSXML.VALUE_ATT, "all");
+	    doc_meta_request.appendChild(doc_param_list);
+
+	}
+	
+	// process the metadata requests
+	Element metadata_response = (Element)this.mr.process(metadata_message);
+	if (did_classifier) {
+	    // the classifier one will be the first response
+	    // add the metadata lists for each node back into the 
+	    // page_classifier nodes
+	    path = GSPath.appendLink(GSXML.RESPONSE_ELEM, 
+				   GSXML.CLASS_NODE_ELEM+GSXML.LIST_MODIFIER);
+	    NodeList meta_response_cls = GSXML.getNodeByPath(metadata_response, path).getChildNodes();
+	    for (int i = 0; i < cl_nodes.getLength(); i++) {
+		GSXML.mergeMetadataLists(cl_nodes.item(i), meta_response_cls.item(i));
+	    }
+	}
+	if (did_documents) {
+	    NodeList meta_response_docs = null;
+	    if (!did_classifier) {
+		// its the first response
+		path = GSPath.appendLink(GSXML.RESPONSE_ELEM, 
+					 GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+		meta_response_docs = GSXML.getNodeByPath(metadata_response, path).getChildNodes();
+	    } else { // its the second response
+		meta_response_docs = GSXML.getChildByTagName(metadata_response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(1), GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER).getChildNodes();
+	    }
+	    
+	    for (int i = 0; i < doc_nodes.getLength(); i++) {
+		GSXML.mergeMetadataLists(doc_nodes.item(i), meta_response_docs.item(i));
+	    }
+	}
+	    
+
+	logger.debug("(BrowseAction) Page:\n" + this.converter.getPrettyString(page_response));
+	return page_response;
+    }
+
+    protected Element unknownBrowse(Element page, Element request, String browse_type) {
+	logger.error("unknown browse subtype: "+browse_type);
+	return null;
+    }
+}
+
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/DocumentAction.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/DocumentAction.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/DocumentAction.java	(revision 14125)
@@ -0,0 +1,847 @@
+/*
+ *    DocumentAction.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.action;
+
+// Greenstone classes
+import org.greenstone.gsdl3.core.ModuleInterface;
+import org.greenstone.gsdl3.util.*;
+
+// XML classes
+import org.w3c.dom.Document; 
+import org.w3c.dom.Element; 
+import org.w3c.dom.Node; 
+import org.w3c.dom.Text;
+import org.w3c.dom.NodeList;
+
+// General Java classes
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.io.File;
+
+import org.apache.log4j.*;
+
+/** Action class for retrieving Documents  via the message router
+ */
+public class DocumentAction extends Action {
+
+   static Logger logger = Logger.getLogger(org.greenstone.gsdl3.action.DocumentAction.class.getName());
+
+    // this is used to specify that the sibling nodes of a selected one should be obtained
+    public static final String SIBLING_ARG = "sib";
+    public static final String GOTO_PAGE_ARG = "gp";
+    public static final String ENRICH_DOC_ARG = "end";
+    
+    /** if this is set to true, when a document is displayed, any annotation
+     * type services (enrich) will be offered to the user as well */
+    protected boolean provide_annotations = false; 
+    
+    protected boolean highlight_query_terms = false;
+
+    public boolean configure() {
+	super.configure();
+	String highlight = (String)config_params.get("highlightQueryTerms");
+	if (highlight != null && highlight.equals("true")) {
+	    highlight_query_terms = true;
+	}
+	String annotate = (String)config_params.get("displayAnnotationService");
+	if (annotate != null && annotate.equals("true")) {
+	    provide_annotations = true;
+	}
+	return true;
+    }
+    public Element process (Element message)
+    {
+	// for now, no subaction eventually we may want to have subactions such as text assoc or something ?
+	
+	// the response
+	Element result = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element page_response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.appendChild(page_response);
+
+	// get the request - assume only one
+	Element request = (Element)GSXML.getChildByTagName(message, GSXML.REQUEST_ELEM);
+	Element cgi_paramList = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	HashMap params = GSXML.extractParams(cgi_paramList, false);
+
+	// just in case there are some that need to get passed to the services
+	HashMap service_params = (HashMap)params.get("s0"); 
+
+	String collection = (String) params.get(GSParams.COLLECTION);
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	String uid = request.getAttribute(GSXML.USER_ID_ATT);
+	String document_name = (String) params.get(GSParams.DOCUMENT);
+	if (document_name == null || document_name.equals("")) {
+	    logger.error("no document specified!");
+	    return result;
+	}
+	String document_type = (String) params.get(GSParams.DOCUMENT_TYPE);
+	if (document_type == null) {
+	    document_type = "simple";
+	}
+	//whether to retrieve siblings or not
+	boolean get_siblings = false;
+	String sibs = (String) params.get(SIBLING_ARG);
+	if (sibs != null && sibs.equals("1")) {
+	    get_siblings = true;
+	}
+	
+	String sibling_num = (String) params.get(GOTO_PAGE_ARG);
+	if (sibling_num != null && !sibling_num.equals("")) {
+	    // we have to modify the doc name
+	    document_name = document_name+"."+sibling_num+".ss";
+	}
+	
+	boolean expand_document = false;
+	String ed_arg = (String) params.get(GSParams.EXPAND_DOCUMENT);
+	if (ed_arg != null && ed_arg.equals("1")) {
+	    expand_document = true;
+	}
+       
+
+	boolean expand_contents = false;
+	if (expand_document) { // we always expand the contents with the text
+	    expand_contents = true;
+	} else {
+	    String ec_arg = (String) params.get(GSParams.EXPAND_CONTENTS);
+	    if (ec_arg != null && ec_arg.equals("1")) {
+		expand_contents = true;
+	    }
+	}
+	// get the additional data needed for the page
+	getBackgroundData(page_response, collection, lang, uid);
+	Element format_elem = (Element)GSXML.getChildByTagName(page_response, GSXML.FORMAT_ELEM);
+	
+	// the_document is where all the doc info - structure and metadata etc
+	// is added into, to be returned in the page
+	Element the_document = this.doc.createElement(GSXML.DOCUMENT_ELEM);
+	page_response.appendChild(the_document);
+
+	// set the doctype from the cgi arg as an attribute
+	the_document.setAttribute(GSXML.DOC_TYPE_ATT, document_type);
+
+	// create a basic doc list containing the current node
+	Element basic_doc_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	Element current_doc = this.doc.createElement(GSXML.DOC_NODE_ELEM);
+	basic_doc_list.appendChild(current_doc);
+	current_doc.setAttribute(GSXML.NODE_ID_ATT, document_name);
+	
+	// Create a parameter list to specify the required structure information
+	Element ds_param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	
+	if (service_params != null) {
+	    GSXML.addParametersToList(this.doc, ds_param_list, service_params);
+	}
+
+	Element ds_param = null; 
+	boolean get_structure = false;
+	boolean get_structure_info = false;
+	if (document_type.equals("paged")) {
+	    get_structure_info = true;
+	    // get teh info needed for paged naviagtion
+	    ds_param = this.doc.createElement(GSXML.PARAM_ELEM);
+	    ds_param_list.appendChild(ds_param);
+	    ds_param.setAttribute(GSXML.NAME_ATT, "info");
+	    ds_param.setAttribute(GSXML.VALUE_ATT, "numSiblings");
+	    ds_param = this.doc.createElement(GSXML.PARAM_ELEM);
+	    ds_param_list.appendChild(ds_param);
+	    ds_param.setAttribute(GSXML.NAME_ATT, "info");
+	    ds_param.setAttribute(GSXML.VALUE_ATT, "numChildren");
+	    ds_param = this.doc.createElement(GSXML.PARAM_ELEM);
+	    ds_param_list.appendChild(ds_param);
+	    ds_param.setAttribute(GSXML.NAME_ATT, "info");
+	    ds_param.setAttribute(GSXML.VALUE_ATT, "siblingPosition");
+	    
+	} else if (document_type.equals("hierarchy")){
+	    get_structure = true;
+	    if (expand_contents) {
+		ds_param = this.doc.createElement(GSXML.PARAM_ELEM);
+		ds_param_list.appendChild(ds_param);
+		ds_param.setAttribute(GSXML.NAME_ATT, "structure");
+		ds_param.setAttribute(GSXML.VALUE_ATT, "entire");
+	    } else {
+		// get the info needed for table of contents
+		ds_param = this.doc.createElement(GSXML.PARAM_ELEM);
+		ds_param_list.appendChild(ds_param);
+		ds_param.setAttribute(GSXML.NAME_ATT, "structure");
+		ds_param.setAttribute(GSXML.VALUE_ATT, "ancestors");
+		ds_param = this.doc.createElement(GSXML.PARAM_ELEM);
+		ds_param_list.appendChild(ds_param);
+		ds_param.setAttribute(GSXML.NAME_ATT, "structure");
+		ds_param.setAttribute(GSXML.VALUE_ATT, "children");
+		if (get_siblings) {
+		    ds_param = this.doc.createElement(GSXML.PARAM_ELEM);
+		    ds_param_list.appendChild(ds_param);
+		    ds_param.setAttribute(GSXML.NAME_ATT, "structure");
+		    ds_param.setAttribute(GSXML.VALUE_ATT, "siblings");
+		}
+	    }
+	} else {
+	    // we dont need any structure
+	}
+
+	boolean has_dummy = false;
+	if (get_structure || get_structure_info) {
+
+	    // Build a request to obtain the document structure
+	    Element ds_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	    String to = GSPath.appendLink(collection, "DocumentStructureRetrieve");// Hard-wired?
+	    Element ds_request = GSXML.createBasicRequest(this.doc,GSXML.REQUEST_TYPE_PROCESS, to, lang, uid); 
+	    ds_message.appendChild(ds_request);
+	    ds_request.appendChild(ds_param_list);
+	    
+	    // create a doc_node_list and put in the doc_node that we are interested in
+	    ds_request.appendChild(basic_doc_list);
+	    
+	    // Process the document structure retrieve message
+	    Element ds_response_message = (Element) this.mr.process(ds_message);
+	    if (processErrorElements(ds_response_message, page_response)) {
+		return result;
+	    }
+
+	    // get the info and print out
+	    String path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	    path = GSPath.appendLink(path, GSXML.DOC_NODE_ELEM);
+	    path = GSPath.appendLink(path, "nodeStructureInfo");
+	    Element ds_response_struct_info = (Element) GSXML.getNodeByPath(ds_response_message, path);
+	    // get the doc_node bit 
+	    if (ds_response_struct_info != null) {
+		the_document.appendChild(this.doc.importNode(ds_response_struct_info, true)); 
+	    }
+	    path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	    path = GSPath.appendLink(path, GSXML.DOC_NODE_ELEM);
+	    path = GSPath.appendLink(path, GSXML.NODE_STRUCTURE_ELEM);
+	    Element ds_response_structure = (Element) GSXML.getNodeByPath(ds_response_message, path);
+	    
+	    if (ds_response_structure != null) {
+		// add the contents of the structure bit into the_document
+		NodeList structs = ds_response_structure.getChildNodes();
+		for (int i=0; i<structs.getLength();i++) {
+		    the_document.appendChild(this.doc.importNode(structs.item(i), true));
+		}
+	    } else {
+		// no structure nodes, so put in a dummy doc node
+		Element doc_node = this.doc.createElement(GSXML.DOC_NODE_ELEM);
+		doc_node.setAttribute(GSXML.NODE_ID_ATT, document_name);
+		the_document.appendChild(doc_node);
+		has_dummy = true;
+	    }
+	} else { // a simple type - we dont have a dummy node for simple
+	    // should think about this more
+	    // no structure request, so just put in a dummy doc node
+	    Element doc_node = this.doc.createElement(GSXML.DOC_NODE_ELEM);
+	    doc_node.setAttribute(GSXML.NODE_ID_ATT, document_name);
+	    the_document.appendChild(doc_node);
+	    has_dummy = true;
+	}
+	
+	// Build a request to obtain some document metadata
+	Element dm_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	String to = GSPath.appendLink(collection, "DocumentMetadataRetrieve");  // Hard-wired?
+	Element dm_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, lang, uid);
+	dm_message.appendChild(dm_request);
+	// Create a parameter list to specify the required metadata information
+	
+	HashSet meta_names = new HashSet();
+	meta_names.add("Title"); // the default
+	if (format_elem != null) {
+	    extractMetadataNames(format_elem, meta_names);
+	}
+	
+	Element dm_param_list = createMetadataParamList(meta_names);
+	if (service_params != null) {
+	    GSXML.addParametersToList(this.doc, dm_param_list, service_params);
+	}
+	
+	dm_request.appendChild(dm_param_list);
+	
+	
+	// create the doc node list for the metadata request
+	Element dm_doc_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	dm_request.appendChild(dm_doc_list);
+
+	// Add each node from the structure response into the metadata request
+	NodeList doc_nodes = the_document.getElementsByTagName(GSXML.DOC_NODE_ELEM);
+	for (int i = 0; i < doc_nodes.getLength(); i++) {
+	    Element doc_node = (Element) doc_nodes.item(i);
+	    String doc_node_id = doc_node.getAttribute(GSXML.NODE_ID_ATT);
+
+	    // Add the documentNode to the list
+	    Element dm_doc_node = this.doc.createElement(GSXML.DOC_NODE_ELEM);
+	    dm_doc_list.appendChild(dm_doc_node);
+	    dm_doc_node.setAttribute(GSXML.NODE_ID_ATT, doc_node_id);
+	    dm_doc_node.setAttribute(GSXML.NODE_TYPE_ATT,
+				     doc_node.getAttribute(GSXML.NODE_TYPE_ATT));
+	}
+
+	// we also want a metadata request to the top level document to get
+	// assocfilepath - this could be cached too
+	Element doc_meta_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, lang, uid);
+	dm_message.appendChild(doc_meta_request);
+	Element doc_meta_param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (service_params != null) {
+	    GSXML.addParametersToList(this.doc, doc_meta_param_list, service_params);
+	}
+
+	doc_meta_request.appendChild(doc_meta_param_list);
+	Element doc_param = this.doc.createElement(GSXML.PARAM_ELEM);
+	doc_meta_param_list.appendChild(doc_param);
+	doc_param.setAttribute(GSXML.NAME_ATT, "metadata");
+	doc_param.setAttribute(GSXML.VALUE_ATT, "archivedir");
+
+	// create the doc node list for the metadata request
+	Element doc_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	doc_meta_request.appendChild(doc_list);
+
+	Element doc_node = this.doc.createElement(GSXML.DOC_NODE_ELEM);
+	// the node we want is the root document node
+	doc_node.setAttribute(GSXML.NODE_ID_ATT, document_name+".rt");
+	doc_list.appendChild(doc_node);
+	Element dm_response_message = (Element) this.mr.process(dm_message);
+	if (processErrorElements(dm_response_message, page_response)) {
+	    return result;
+	}
+
+	String path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	Element dm_response_doc_list = (Element) GSXML.getNodeByPath(dm_response_message, path);
+
+	// Merge the metadata with the structure information
+	NodeList dm_response_docs = dm_response_doc_list.getChildNodes();
+	for (int i = 0; i < doc_nodes.getLength(); i++) {
+	    GSXML.mergeMetadataLists(doc_nodes.item(i), dm_response_docs.item(i));
+	}
+	// get teh top level doc metadata out
+	Element doc_meta_response = (Element)dm_response_message.getElementsByTagName(GSXML.RESPONSE_ELEM).item(1);
+	Element doc_meta_list = (Element)GSXML.getNodeByPath(doc_meta_response, "documentNodeList/documentNode/metadataList");
+	if (doc_meta_list != null) {
+	    the_document.appendChild(this.doc.importNode(doc_meta_list, true));
+	}
+	// Build a request to obtain some document content
+	Element dc_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	to = GSPath.appendLink(collection, "DocumentContentRetrieve");  // Hard-wired?
+	Element dc_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, lang, uid);
+	dc_message.appendChild(dc_request);
+	
+
+	// Create a parameter list to specify the request parameters - empty for now
+	Element dc_param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (service_params != null) {
+	    GSXML.addParametersToList(this.doc, dc_param_list, service_params);
+	}
+
+	dc_request.appendChild(dc_param_list);
+
+	// get the content
+	// the doc list for the content request is the same as the one for the structure request unless we want the whole document, in which case its the same as for the metadata request.
+	if (expand_document) {
+	    dc_request.appendChild(dm_doc_list);
+	} else {
+	    dc_request.appendChild(basic_doc_list);
+	}
+	logger.debug("request = "+converter.getString(dc_message));
+	Element dc_response_message = (Element) this.mr.process(dc_message);
+	if (processErrorElements(dc_response_message, page_response)) {
+	    return result;
+	}
+
+	Element dc_response_doc_list = (Element) GSXML.getNodeByPath(dc_response_message, path);
+
+	if (expand_document) {
+	    // Merge the content with the structure information
+	    NodeList dc_response_docs = dc_response_doc_list.getChildNodes();
+	    for (int i = 0; i < doc_nodes.getLength(); i++) {
+		Node content = GSXML.getChildByTagName((Element)dc_response_docs.item(i), "nodeContent");
+		if (content != null) {
+		    doc_nodes.item(i).appendChild(this.doc.importNode(content, true));
+		}
+		//GSXML.mergeMetadataLists(doc_nodes.item(i), dm_response_docs.item(i));
+	    }
+	} else {
+	    
+	    //path = GSPath.appendLink(path, GSXML.DOC_NODE_ELEM);
+	    Element dc_response_doc = (Element) GSXML.getChildByTagName(dc_response_doc_list, GSXML.DOC_NODE_ELEM);
+	    Element dc_response_doc_content = (Element) GSXML.getChildByTagName(dc_response_doc, GSXML.NODE_CONTENT_ELEM);
+	    
+	    if (dc_response_doc_content == null) {
+		// no content to add
+		return result;
+	    }
+	    if (highlight_query_terms) {
+		dc_response_doc.removeChild(dc_response_doc_content);
+		
+		dc_response_doc_content = highlightQueryTerms(request, dc_response_doc_content);
+		dc_response_doc.appendChild(dc_response_doc.getOwnerDocument().importNode(dc_response_doc_content, true));
+	    }
+	    
+	
+	if (provide_annotations) {
+	    String service_selected = (String)params.get(ENRICH_DOC_ARG);
+	    if (service_selected != null && service_selected.equals("1")) {
+		// now we can modifiy the response doc if needed
+		String enrich_service = (String)params.get(GSParams.SERVICE);
+		// send a message to the service
+		Element enrich_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+		Element enrich_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, enrich_service, lang, uid);
+		enrich_message.appendChild(enrich_request);
+		// check for parameters
+		HashMap e_service_params = (HashMap)params.get("s1");
+		if (e_service_params != null) { 
+		    Element enrich_pl = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+		    GSXML.addParametersToList(this.doc, enrich_pl, e_service_params); 
+		    enrich_request.appendChild(enrich_pl);
+		}
+		Element e_doc_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+		enrich_request.appendChild(e_doc_list);
+		e_doc_list.appendChild(this.doc.importNode(dc_response_doc, true));
+		
+		Element enrich_response = this.mr.process(enrich_message);
+		
+		String [] links = {GSXML.RESPONSE_ELEM, GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER, GSXML.DOC_NODE_ELEM, GSXML.NODE_CONTENT_ELEM};
+		path = GSPath.createPath(links);
+		dc_response_doc_content = (Element)GSXML.getNodeByPath(enrich_response, path);
+		
+	    } 
+	} // if provide_annotations
+
+	
+	// use the returned id rather than the sent one cos there may have
+	// been modifiers such as .pr that are removed.
+	String modified_doc_id = dc_response_doc.getAttribute(GSXML.NODE_ID_ATT);
+	the_document.setAttribute("selectedNode", modified_doc_id);
+	if (has_dummy) {
+	    // change the id if necessary and add the content
+	    Element dummy_node = (Element)doc_nodes.item(0);
+	    
+	    dummy_node.setAttribute(GSXML.NODE_ID_ATT, modified_doc_id);
+	    dummy_node.appendChild(this.doc.importNode(dc_response_doc_content, true));
+	    // hack for simple type
+	    if (document_type.equals("simple")) {
+		// we dont want the internal docNode, just want the content and metadata in the document
+		// rethink this!!
+		the_document.removeChild(dummy_node);
+
+		NodeList dummy_children = dummy_node.getChildNodes();
+		//for (int i=0; i<dummy_children.getLength(); i++) {
+		for (int i=dummy_children.getLength()-1; i>=0; i--) {
+		    the_document.appendChild(dummy_children.item(i));
+		    
+		}
+	    }
+	} else {
+	    // Merge the document content with the metadata and structure information
+	    for (int i = 0; i < doc_nodes.getLength(); i++) {
+		Node dn = doc_nodes.item(i);
+		String dn_id = ((Element)dn).getAttribute(GSXML.NODE_ID_ATT);
+		if (dn_id.equals(modified_doc_id)) {
+		    dn.appendChild(this.doc.importNode(dc_response_doc_content, true));
+		    break;
+		}
+	    }
+	}
+	}
+	logger.debug("(DocumentAction) Page:\n" + this.converter.getPrettyString(result));
+	return result;
+    }
+    
+    /** tell the param class what its arguments are 
+     * if an action has its own arguments, this should add them to the params
+     * object - particularly important for args that should not be saved */
+    public boolean getActionParameters(GSParams params) {
+	params.addParameter(GOTO_PAGE_ARG, false);
+	params.addParameter(ENRICH_DOC_ARG, false);
+ 	return true;
+    }
+
+
+    /** this method gets the collection description, the format info, the
+     * list of enrich services, etc - stuff that is needed for the page,
+     * but is the same whatever the query is - should be cached */
+    protected  boolean getBackgroundData(Element page_response, 
+					 String collection, String lang,
+					 String uid) {
+
+	// create a message to process - contains requests for the collection 
+	// description, the format element, the enrich services on offer
+	// these could all be cached
+	Element info_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	String path = GSPath.appendLink(collection, "DocumentContentRetrieve");
+	// the format request - ignore for now, where does this request go to??
+	Element format_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_FORMAT, path, lang, uid);
+	info_message.appendChild(format_request);
+
+	// the enrich_services request - only do this if provide_annotations is true
+
+	if (provide_annotations) {
+	    Element enrich_services_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, "", lang, uid);
+	    enrich_services_request.setAttribute(GSXML.INFO_ATT, "serviceList");
+	    info_message.appendChild(enrich_services_request);
+	}
+	
+	Element info_response = (Element)this.mr.process(info_message);
+
+	// the collection is the first response
+	NodeList responses = info_response.getElementsByTagName(GSXML.RESPONSE_ELEM);
+	Element format_resp = (Element) responses.item(0);
+	
+	Element format_elem = (Element)GSXML.getChildByTagName(format_resp, GSXML.FORMAT_ELEM);
+	if (format_elem != null) {
+	    logger.debug("doc action found a format statement");
+	    // set teh format type
+	    format_elem.setAttribute(GSXML.TYPE_ATT, "display");  
+	    page_response.appendChild(this.doc.importNode(format_elem, true));
+	}
+
+	if (provide_annotations) {
+	    Element services_resp = (Element)responses.item(1); 
+
+	    // a new message for the mr
+	    Element enrich_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	    
+	    NodeList e_services = services_resp.getElementsByTagName(GSXML.SERVICE_ELEM);
+	    boolean service_found = false;
+	    for (int j=0; j<e_services.getLength(); j++) {
+		if (((Element)e_services.item(j)).getAttribute(GSXML.TYPE_ATT).equals("enrich")) {
+		    Element s = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, ((Element)e_services.item(j)).getAttribute(GSXML.NAME_ATT), lang, uid);
+		    enrich_message.appendChild(s);
+		    service_found = true;
+		}
+	    }
+	    if (service_found) {
+		Element enrich_response = this.mr.process(enrich_message);
+
+		NodeList e_responses = enrich_response.getElementsByTagName(GSXML.RESPONSE_ELEM);
+		Element service_list = this.doc.createElement(GSXML.SERVICE_ELEM + GSXML.LIST_MODIFIER);
+		for (int i=0; i<e_responses.getLength(); i++) {
+		    Element e_resp = (Element)e_responses.item(i);
+		    Element e_service = (Element)this.doc.importNode(GSXML.getChildByTagName(e_resp, GSXML.SERVICE_ELEM), true); 
+		    e_service.setAttribute(GSXML.NAME_ATT, e_resp.getAttribute(GSXML.FROM_ATT));
+		    service_list.appendChild(e_service);
+		}
+		page_response.appendChild(service_list);
+	    }
+	} // if provide_annotations
+	return true;
+	    
+    }
+
+    /** this involves a bit of a hack to get the equivalent query terms - has to requery the query service - uses the last selected service name. (if it ends in query). should this action do the query or should it send a message to the query action? but that will involve lots of extra stuff. also doesn't handle phrases properly - just highlights all the terms found in the text.
+     */
+    protected Element highlightQueryTerms(Element request, Element dc_response_doc_content) {
+
+	// do the query again to get term info 
+	Element cgi_param_list = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	HashMap params = GSXML.extractParams(cgi_param_list, false);
+	
+	HashMap previous_params = (HashMap)params.get("p");
+	if (previous_params == null) {
+	    return dc_response_doc_content;
+	}
+       	String service_name = (String)previous_params.get(GSParams.SERVICE);
+	if (service_name == null || !service_name.endsWith("Query")) { // hack for now - we only do highlighting if we were in a query last - ie not if we were in a browse thingy
+	    logger.error("invalid service, not doing highlighting");
+	    return dc_response_doc_content;
+	}
+	String collection = (String)params.get(GSParams.COLLECTION);
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	String uid = request.getAttribute(GSXML.USER_ID_ATT);
+	String to = GSPath.appendLink(collection, service_name);
+	
+	Element mr_query_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element mr_query_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, lang, uid);
+	mr_query_message.appendChild(mr_query_request);
+	
+	// paramList
+	HashMap service_params = (HashMap)params.get("s1");
+	
+	Element query_param_list = this.doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
+	GSXML.addParametersToList(this.doc, query_param_list, service_params);
+	mr_query_request.appendChild(query_param_list);
+
+	// do the query
+       	Element mr_query_response = (Element)this.mr.process(mr_query_message);
+	
+	String path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.TERM_ELEM+GSXML.LIST_MODIFIER);
+	Element query_term_list_element = (Element) GSXML.getNodeByPath(mr_query_response, path);
+	if (query_term_list_element == null) {
+	    // no term info
+	    logger.error("No query term information.\n");
+	    return dc_response_doc_content;
+	} 
+
+	String content = GSXML.getNodeText(dc_response_doc_content);
+
+	String metadata_path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+	Element metadata_list = (Element) GSXML.getNodeByPath(mr_query_response, metadata_path);
+
+	HashSet query_term_variants = new HashSet();
+	NodeList equivalent_terms_nodelist = query_term_list_element.getElementsByTagName("equivTermList");
+	for (int i = 0; i < equivalent_terms_nodelist.getLength(); i++) {
+	    Element equivalent_terms_element = (Element) equivalent_terms_nodelist.item(i);
+	    String[] equivalent_terms = GSXML.getAttributeValuesFromList(equivalent_terms_element, GSXML.NAME_ATT);
+	    for (int j = 0; j < equivalent_terms.length; j++) {
+		query_term_variants.add(equivalent_terms[j]);
+	    }
+	}
+
+	ArrayList phrase_query_term_variants_hierarchy = new ArrayList();
+
+	Element query_element = GSXML.getNamedElement(metadata_list, GSXML.METADATA_ELEM, GSXML.NAME_ATT, "query");
+	String performed_query = GSXML.getNodeText(query_element) + " ";
+
+	ArrayList phrase_query_p_term_variants_list = new ArrayList();
+	int term_start = 0;
+	boolean in_term = false;
+	boolean in_phrase = false;
+	for (int i = 0; i < performed_query.length(); i++) {
+	    char character = performed_query.charAt(i);
+	    boolean is_character_letter_or_digit = Character.isLetterOrDigit(character);
+
+	    // Has a query term just started?
+	    if (in_term == false && is_character_letter_or_digit == true) {
+		in_term = true;
+		term_start = i;
+	    }
+
+	    // Or has a term just finished?
+	    else if (in_term == true && is_character_letter_or_digit == false) {
+		in_term = false;
+		String term = performed_query.substring(term_start, i);
+				
+		Element term_element = GSXML.getNamedElement(query_term_list_element, GSXML.TERM_ELEM, GSXML.NAME_ATT, term);
+		if (term_element != null) {
+		    
+		    HashSet phrase_query_p_term_x_variants = new HashSet();
+		    
+		    NodeList term_equivalent_terms_nodelist = term_element.getElementsByTagName("equivTermList");
+		    for (int j = 0; j < term_equivalent_terms_nodelist.getLength(); j++) {
+			Element term_equivalent_terms_element = (Element) term_equivalent_terms_nodelist.item(j);
+			String[] term_equivalent_terms = GSXML.getAttributeValuesFromList(term_equivalent_terms_element, GSXML.NAME_ATT);
+			for (int k = 0; k < term_equivalent_terms.length; k++) {
+			    phrase_query_p_term_x_variants.add(term_equivalent_terms[k]);
+			}
+		    }
+		    phrase_query_p_term_variants_list.add(phrase_query_p_term_x_variants);
+		    
+		    if (in_phrase == false) {
+			phrase_query_term_variants_hierarchy.add(phrase_query_p_term_variants_list);
+			phrase_query_p_term_variants_list = new ArrayList();
+		    }
+		}
+	    }
+	    // Watch for phrases (surrounded by quotes)
+	    if (character == '\"') {
+		// Has a phrase just started?
+		if (in_phrase == false) {
+		    in_phrase = true;
+		}
+		// Or has a phrase just finished?
+		else if (in_phrase == true) {
+		    in_phrase = false;
+		    phrase_query_term_variants_hierarchy.add(phrase_query_p_term_variants_list);
+		}
+
+		phrase_query_p_term_variants_list = new ArrayList();
+	    }
+	}
+
+	return highlightQueryTermsInternal(content, query_term_variants, phrase_query_term_variants_hierarchy);
+    }
+
+
+    /**
+     * Highlights query terms in a piece of text.
+     */
+    private Element highlightQueryTermsInternal(String content, HashSet query_term_variants, ArrayList phrase_query_term_variants_hierarchy)
+    {
+	// Convert the content string to an array of characters for speed
+	char[] content_characters = new char[content.length()];
+	content.getChars(0, content.length(), content_characters, 0);
+
+	// Now skim through the content, identifying word matches
+	ArrayList word_matches = new ArrayList();
+	int word_start = 0;
+	boolean in_word = false;
+	boolean preceding_word_matched = false;
+	for (int i = 0; i < content_characters.length; i++) {
+	    boolean is_character_letter_or_digit = Character.isLetterOrDigit(content_characters[i]);
+
+	    // Has a word just started?
+	    if (in_word == false && is_character_letter_or_digit == true) {
+		in_word = true;
+		word_start = i;
+	    }
+
+	    // Or has a word just finished?
+	    else if (in_word == true && is_character_letter_or_digit == false) {
+		in_word = false;
+
+		// Check if the word matches any of the query term equivalents
+		String word = new String(content_characters, word_start, (i - word_start));
+		if (query_term_variants.contains(word)) {
+		    // We have found a matching word, so remember its location
+		    word_matches.add(new WordMatch(word, word_start, i, preceding_word_matched));
+		    preceding_word_matched = true;
+ 		}
+		else {
+		    preceding_word_matched = false;
+		}
+	    }
+	}
+
+	// Don't forget the last word...
+	if (in_word == true) {
+	    // Check if the word matches any of the query term equivalents
+	    String word = new String(content_characters, word_start, (content_characters.length - word_start));
+	    if (query_term_variants.contains(word)) {
+		// We have found a matching word, so remember its location
+		word_matches.add(new WordMatch(word, word_start, content_characters.length, preceding_word_matched));
+	    }
+	}
+
+	ArrayList highlight_start_positions = new ArrayList();
+	ArrayList highlight_end_positions = new ArrayList();
+
+	// Deal with phrases now
+	ArrayList partial_phrase_matches = new ArrayList();
+	for (int i = 0; i < word_matches.size(); i++) {
+	    WordMatch word_match = (WordMatch) word_matches.get(i);
+
+ 	    // See if any partial phrase matches are extended by this word
+ 	    if (word_match.preceding_word_matched) {
+ 		for (int j = partial_phrase_matches.size() - 1; j >= 0; j--) {
+ 		    PartialPhraseMatch partial_phrase_match = (PartialPhraseMatch) partial_phrase_matches.remove(j);
+		    ArrayList phrase_query_p_term_variants_list = (ArrayList) phrase_query_term_variants_hierarchy.get(partial_phrase_match.query_phrase_number);
+ 		    HashSet phrase_query_p_term_x_variants = (HashSet) phrase_query_p_term_variants_list.get(partial_phrase_match.num_words_matched);
+ 		    if (phrase_query_p_term_x_variants.contains(word_match.word)) {
+ 			partial_phrase_match.num_words_matched++;
+
+ 			// Has a complete phrase match occurred?
+ 			if (partial_phrase_match.num_words_matched == phrase_query_p_term_variants_list.size()) {
+ 			    // Check for overlaps by looking at the previous highlight range
+ 			    if (!highlight_end_positions.isEmpty()) {
+ 				int last_highlight_index = highlight_end_positions.size() - 1;
+ 				int last_highlight_end = ((Integer) highlight_end_positions.get(last_highlight_index)).intValue();
+ 				if (last_highlight_end > partial_phrase_match.start_position) {
+ 				    // There is an overlap, so remove the previous phrase match
+ 				    int last_highlight_start = ((Integer) highlight_start_positions.remove(last_highlight_index)).intValue();
+ 				    highlight_end_positions.remove(last_highlight_index);
+ 				    partial_phrase_match.start_position = last_highlight_start;
+ 				}
+ 			    }
+
+ 			    highlight_start_positions.add(new Integer(partial_phrase_match.start_position));
+ 			    highlight_end_positions.add(new Integer(word_match.end_position));
+ 			}
+ 			// No, but add the partial match back into the list for next time
+ 			else {
+ 			    partial_phrase_matches.add(partial_phrase_match);
+ 			}
+ 		    }
+ 		}
+ 	    }
+ 	    else {
+ 		partial_phrase_matches.clear();
+ 	    }
+
+	    // See if this word is at the start of any of the phrases
+	    for (int p = 0; p < phrase_query_term_variants_hierarchy.size(); p++) {
+		ArrayList phrase_query_p_term_variants_list = (ArrayList) phrase_query_term_variants_hierarchy.get(p);
+		HashSet phrase_query_p_term_1_variants = (HashSet) phrase_query_p_term_variants_list.get(0);
+		if (phrase_query_p_term_1_variants.contains(word_match.word)) {
+		    // If this phrase is just one word long, we have a complete match
+		    if (phrase_query_p_term_variants_list.size() == 1) {
+			highlight_start_positions.add(new Integer(word_match.start_position));
+			highlight_end_positions.add(new Integer(word_match.end_position));
+		    }
+		    // Otherwise we have the start of a potential phrase match
+		    else {
+			partial_phrase_matches.add(new PartialPhraseMatch(word_match.start_position, p));
+		    }
+		}
+	    }
+	}
+
+	// Now add the annotation tags into the document at the correct points
+	Element content_element = this.doc.createElement(GSXML.NODE_CONTENT_ELEM);
+
+ 	int last_wrote = 0;
+	for (int i = 0; i < highlight_start_positions.size(); i++) {
+	    int highlight_start = ((Integer) highlight_start_positions.get(i)).intValue();
+	    int highlight_end = ((Integer) highlight_end_positions.get(i)).intValue();
+
+	    // Print anything before the highlight range
+	    if (last_wrote < highlight_start) {
+		String preceding_text = new String(content_characters, last_wrote, (highlight_start - last_wrote));
+		// System.err.print(preceding_text);
+		content_element.appendChild(this.doc.createTextNode(preceding_text));
+	    }
+
+	    // Print the highlight text, annotated
+	    if (highlight_end > last_wrote) {
+		String highlight_text = new String(content_characters, highlight_start, (highlight_end - highlight_start));
+		// System.err.print("|" + highlight_text + "|");
+		Element annotation_element = GSXML.createTextElement(this.doc, "annotation", highlight_text);
+		annotation_element.setAttribute("type", "query_term");
+		content_element.appendChild(annotation_element);
+		last_wrote = highlight_end;
+	    }
+	}
+
+	// Finish off any unwritten text
+	if (last_wrote < content_characters.length) {
+	    String remaining_text = new String(content_characters, last_wrote, (content_characters.length - last_wrote));
+	    // System.err.print(remaining_text);
+	    content_element.appendChild(this.doc.createTextNode(remaining_text));
+	}
+
+	return content_element;
+    }
+
+
+    static private class WordMatch
+    {
+	public String word;
+	public int start_position;
+	public int end_position;
+	public boolean preceding_word_matched;
+
+	public WordMatch(String word, int start_position, int end_position, boolean preceding_word_matched)
+	{
+	    this.word = word;
+	    this.start_position = start_position;
+	    this.end_position = end_position;
+	    this.preceding_word_matched = preceding_word_matched;
+	}
+    }
+
+
+    static private class PartialPhraseMatch
+    {
+	public int start_position;
+	public int query_phrase_number;
+	public int num_words_matched;
+
+	public PartialPhraseMatch(int start_position, int query_phrase_number)
+	{
+	    this.start_position = start_position;
+	    this.query_phrase_number = query_phrase_number;
+	    this.num_words_matched = 1;
+	}
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/GS2BrowseAction.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/GS2BrowseAction.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/GS2BrowseAction.java	(revision 14125)
@@ -0,0 +1,346 @@
+package org.greenstone.gsdl3.action;
+
+import org.greenstone.gsdl3.core.ModuleInterface;
+import org.greenstone.gsdl3.util.*;
+// XML classes
+import org.w3c.dom.Node; 
+import org.w3c.dom.NodeList; 
+import org.w3c.dom.Document; 
+import org.w3c.dom.Element; 
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Vector;
+import java.io.File;
+
+import org.apache.log4j.*;
+
+/** action for GS2 style classifier browsing */
+public class GS2BrowseAction extends Action {
+    
+    public static final String CLASSIFIER_ARG = "cl";
+
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.action.GS2BrowseAction.class.getName());    
+
+    /** process the request */
+    public Element process (Element message) {
+
+	// get the request - assume only one
+	Element request = (Element)GSXML.getChildByTagName(message, GSXML.REQUEST_ELEM);
+
+	// the result
+	Element result = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element response = classifierBrowse(request);
+	result.appendChild(response);
+	return result;
+    }
+    
+
+    protected Element classifierBrowse(Element request) {
+
+	Element page_response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+
+	// extract the params from the cgi-request, and check that we have a coll specified
+	Element cgi_paramList = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	HashMap params = GSXML.extractParams(cgi_paramList, false);
+	
+	String service_name = (String)params.get(GSParams.SERVICE);
+	String collection = (String)params.get(GSParams.COLLECTION);
+	if (collection == null || collection.equals("")) {
+	    logger.error("classifierBrowse, need to specify a collection!");
+	    return page_response;
+	   
+	}
+	
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	String uid = request.getAttribute(GSXML.USER_ID_ATT);
+	String to = GSPath.appendLink(collection, service_name);
+	
+	// the first part of the response is the service description 
+	// for now get this again from the service. 
+	// this should be cached somehow later on. 
+	
+	Element info_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element info_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, to, lang, uid); 
+	info_message.appendChild(info_request);
+	
+	// also get the format stuff now if there is some
+	Element format_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_FORMAT, to, lang, uid);
+	info_message.appendChild(format_request);
+	// process the requests
+
+	Element info_response = (Element) this.mr.process(info_message);
+
+	// the two responses
+	NodeList responses = info_response.getElementsByTagName(GSXML.RESPONSE_ELEM);
+	Element service_response = (Element)responses.item(0);
+	Element format_response = (Element)responses.item(1);
+
+	Element service_description = (Element)GSXML.getChildByTagName(service_response, GSXML.SERVICE_ELEM);
+	page_response.appendChild(this.doc.importNode(service_description, true));
+	
+	// if rt=d, then we are just displaying the service
+	String request_type = (String)params.get(GSParams.REQUEST_TYPE);
+	if (request_type.equals("d")) {
+	    //return the page that we have so far
+	    return page_response;
+	}
+    
+	// get the node that the user has clicked on
+	String classifier_node = (String)params.get(CLASSIFIER_ARG);
+	
+	// if the node is not defined, return the page that we have so far
+	if (classifier_node ==null || classifier_node.equals("")) {
+	    return page_response;
+	}
+	
+	// the id of the classifier is the top id of the selected node
+	String top_id = OID.getTop(classifier_node);
+	HashSet doc_meta_names = new HashSet();
+	HashSet class_meta_names = new HashSet();
+	// add in the defaults
+	doc_meta_names.add("Title");
+	class_meta_names.add("Title");
+	
+	// add the format info into the response
+	Element format_elem = (Element)GSXML.getChildByTagName(format_response, GSXML.FORMAT_ELEM);
+	if (format_elem != null) {
+	    
+	    // find the one for the classifier we are in
+	    Element this_format = GSXML.getNamedElement(format_elem, GSXML.CLASSIFIER_ELEM, GSXML.NAME_ATT, top_id);
+	    if (this_format == null) {
+		this_format = (Element)GSXML.getChildByTagName(format_elem, GSXML.DEFAULT_ELEM);
+	    }
+
+	    if (this_format != null) {
+		Element new_format = GSXML.duplicateWithNewName(this.doc, this_format, GSXML.FORMAT_ELEM, false);
+		extractMetadataNames(new_format, doc_meta_names, class_meta_names);
+		// set the format type
+		new_format.setAttribute(GSXML.TYPE_ATT, "browse");
+
+		page_response.appendChild(new_format);
+	    }
+	}
+	
+	// find out if this classifier is horizontal at top
+	Element class_list = (Element)GSXML.getChildByTagName(service_description, GSXML.CLASSIFIER_ELEM+GSXML.LIST_MODIFIER);
+	Element this_classifier = GSXML.getNamedElement(class_list, GSXML.CLASSIFIER_ELEM, GSXML.NAME_ATT, top_id);
+	boolean horizontal_at_top = false;
+	if (!this_classifier.getAttribute("horizontalAtTop").equals("")) {
+	    horizontal_at_top = true;
+	}
+	if (top_id.equals(classifier_node) && horizontal_at_top) {
+	    // we have asked for a top node - if the first list is horizontal, we will select the first element of that list
+	    // this is a hack. also it craps out if the classifier really isn't horizontalAtTop. - 
+	    classifier_node = classifier_node+".1";
+		    
+	}
+
+	// get the browse structure for the selected node
+	Element classify_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element classify_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, lang, uid);
+	classify_message.appendChild(classify_request);
+	    
+	//Create a parameter list to specify the required structure information
+	// for now, always get ancestors and children
+	Element param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	classify_request.appendChild(param_list);
+	Element param = this.doc.createElement(GSXML.PARAM_ELEM);
+	param_list.appendChild(param);
+	param.setAttribute(GSXML.NAME_ATT, "structure");
+	param.setAttribute(GSXML.VALUE_ATT, "ancestors");
+	param = this.doc.createElement(GSXML.PARAM_ELEM);
+	param_list.appendChild(param);
+	param.setAttribute(GSXML.NAME_ATT, "structure");
+	param.setAttribute(GSXML.VALUE_ATT, "children");
+
+	// put the classifier node into a classifier node list
+	Element classifier_list = this.doc.createElement(GSXML.CLASS_NODE_ELEM+GSXML.LIST_MODIFIER);
+	Element classifier = this.doc.createElement(GSXML.CLASS_NODE_ELEM);
+	classifier.setAttribute(GSXML.NODE_ID_ATT, classifier_node);
+	classifier_list.appendChild(classifier);
+	classify_request.appendChild(classifier_list);
+	    
+	if (horizontal_at_top && !classifier_node.equals(top_id)) {
+	    // also put the top id in, to get the persistant horizontal info
+	    classifier = this.doc.createElement(GSXML.CLASS_NODE_ELEM);
+	    classifier.setAttribute(GSXML.NODE_ID_ATT, top_id);
+	    classifier_list.appendChild(classifier);
+	}
+	// process the request
+	Element classify_response = (Element)this.mr.process(classify_message);
+	String path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.CLASS_NODE_ELEM+GSXML.LIST_MODIFIER);
+	Element class_node_list = (Element)GSXML.getNodeByPath(classify_response, path);
+	
+	path = GSPath.appendLink(GSXML.CLASS_NODE_ELEM, GSXML.NODE_STRUCTURE_ELEM);
+	// assume that we always get back the top level CL1 node - this becomes the page_classifier node
+	path = GSPath.appendLink(path, GSXML.CLASS_NODE_ELEM);
+	Element cl_structure = (Element)GSXML.getNodeByPath(class_node_list,
+							    path);
+	if (cl_structure ==null) {
+	    logger.error("classifier structure request returned no structure");
+	    return page_response;
+	}   
+    
+	Element page_classifier = null;
+	if (horizontal_at_top && !classifier_node.equals(top_id)) {
+	    // get the info for the top node
+	    Element top_node = GSXML.getNamedElement(class_node_list, GSXML.CLASS_NODE_ELEM, GSXML.NODE_ID_ATT, top_id);
+	    if (top_node !=null) {
+		path = GSPath.appendLink(GSXML.NODE_STRUCTURE_ELEM, GSXML.CLASS_NODE_ELEM);
+		Element top_structure = (Element)GSXML.getNodeByPath(top_node, path);	    
+		// add this as the classifier elem
+		page_classifier = GSXML.duplicateWithNewName(this.doc, top_structure,  GSXML.CLASSIFIER_ELEM, true);
+		page_response.appendChild(page_classifier);
+		// now replace the child with the structure from the other request
+		Element new_classifier = (Element)GSXML.getChildByTagName(cl_structure, GSXML.CLASS_NODE_ELEM);
+		String replace_name = new_classifier.getAttribute(GSXML.NODE_ID_ATT);
+		
+		// find the appropriate child
+		Element old_classifier = GSXML.getNamedElement(page_classifier, GSXML.CLASS_NODE_ELEM, GSXML.NODE_ID_ATT, replace_name);
+		page_classifier.replaceChild(this.doc.importNode(new_classifier, true), old_classifier);
+		page_classifier.setAttribute(GSXML.NAME_ATT, top_id);
+	    } else {
+		// add the single classifier node as the page classifier 
+		page_classifier = GSXML.duplicateWithNewName(this.doc, cl_structure,  GSXML.CLASSIFIER_ELEM, true);
+		page_response.appendChild(page_classifier);
+		page_classifier.setAttribute(GSXML.NAME_ATT, top_id);
+	    }
+	    
+	} else {
+	    // add the single classifier node as the page classifier 
+	    page_classifier = GSXML.duplicateWithNewName(this.doc, cl_structure,  GSXML.CLASSIFIER_ELEM, true);
+	    page_response.appendChild(page_classifier);
+	    page_classifier.setAttribute(GSXML.NAME_ATT, top_id);
+	}
+	// get the metadata for each classifier node, 
+	// then for each document node
+
+	Element metadata_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+
+	boolean did_classifier = false;
+	boolean did_documents = false;
+	
+    
+	// if there are classifier nodes 
+	// create a metadata request for the classifier, and add it to 
+	// the the message
+	NodeList cl_nodes = page_classifier.getElementsByTagName(GSXML.CLASS_NODE_ELEM);
+	
+	if (cl_nodes.getLength() > 0) {
+	    did_classifier = true;
+	    Element cl_meta_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to+"MetadataRetrieve", lang, uid);
+	    metadata_message.appendChild(cl_meta_request);
+	    
+	    Element new_cl_nodes_list = this.doc.createElement(GSXML.CLASS_NODE_ELEM+GSXML.LIST_MODIFIER);
+	    cl_meta_request.appendChild(new_cl_nodes_list);
+	    
+	    for (int c=0; c<cl_nodes.getLength(); c++) {
+
+		Element cl = this.doc.createElement(GSXML.CLASS_NODE_ELEM);
+		cl.setAttribute(GSXML.NODE_ID_ATT, ((Element)cl_nodes.item(c)).getAttribute(GSXML.NODE_ID_ATT));
+		new_cl_nodes_list.appendChild(cl);
+	    }
+
+	    // create and add in the param list - for now get all the metadata
+	    // should be based on info sent in from the recept, and the 
+	    // format stuff
+	    Element cl_param_list  = createMetadataParamList(class_meta_names);
+	    cl_meta_request.appendChild(cl_param_list);
+	    
+	}
+
+	// if there are document nodes in the classification (happens 
+	// sometimes), create a second request for document metadata and 
+	// append to the message
+	NodeList doc_nodes = page_classifier.getElementsByTagName(GSXML.DOC_NODE_ELEM);
+	if (doc_nodes.getLength() > 0) {
+	    did_documents = true;
+	    Element doc_meta_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, GSPath.appendLink(collection, "DocumentMetadataRetrieve"), lang, uid);
+	    metadata_message.appendChild(doc_meta_request);
+	    
+	    Element doc_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	    doc_meta_request.appendChild(doc_list);
+	    
+	    for (int c=0; c<doc_nodes.getLength(); c++) {
+		
+		Element d = this.doc.createElement(GSXML.DOC_NODE_ELEM);
+		d.setAttribute(GSXML.NODE_ID_ATT, ((Element)doc_nodes.item(c)).getAttribute(GSXML.NODE_ID_ATT));
+		doc_list.appendChild(d);
+	    }
+
+	    // create and add in the param list - add all for now
+	    Element doc_param_list  = createMetadataParamList(doc_meta_names);
+	    doc_meta_request.appendChild(doc_param_list);
+
+	}
+	
+	// process the metadata requests
+	Element metadata_response = (Element)this.mr.process(metadata_message);
+        if (did_classifier) {
+	    // the classifier one will be the first response
+	    // add the metadata lists for each node back into the 
+	    // page_classifier nodes
+	    path = GSPath.appendLink(GSXML.RESPONSE_ELEM, 
+				   GSXML.CLASS_NODE_ELEM+GSXML.LIST_MODIFIER);
+            Node pathNode = GSXML.getNodeByPath(metadata_response, path);
+            if (pathNode ==null){
+	        return page_response; 
+	    }
+	    NodeList meta_response_cls = pathNode.getChildNodes();
+	    for (int i = 0; i < cl_nodes.getLength(); i++) {
+		GSXML.mergeMetadataLists(cl_nodes.item(i), meta_response_cls.item(i));
+		
+	    }
+	}
+
+	if (did_documents) {
+	    NodeList meta_response_docs = null;
+	    if (!did_classifier) {
+		// its the first response
+		path = GSPath.appendLink(GSXML.RESPONSE_ELEM, 
+					 GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+		Node pathNode = GSXML.getNodeByPath(metadata_response, path);
+		if (pathNode ==null){
+		    return page_response;
+                 }
+
+		meta_response_docs = pathNode.getChildNodes();
+		
+
+	    } else { // its the second response
+                Node nodes = GSXML.getChildByTagName(metadata_response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(1), GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+		if (nodes ==null){
+		    return page_response;
+                 }
+		meta_response_docs = nodes.getChildNodes();
+	    }
+	    
+	    for (int i = 0; i < doc_nodes.getLength(); i++) {
+		GSXML.mergeMetadataLists(doc_nodes.item(i), meta_response_docs.item(i));
+	    }
+	}
+	    
+
+	logger.debug("(GS2BrowseAction) Page:\n" + this.converter.getPrettyString(page_response));
+	return page_response;
+    }
+
+   
+    protected void extractMetadataNames(Element new_format, HashSet doc_meta_names, HashSet class_meta_names) {
+
+	NodeList templates = new_format.getElementsByTagName("gsf:template");
+	for (int i=0; i<templates.getLength(); i++) {
+	    Element template = (Element)templates.item(i);
+	    String match = template.getAttribute("match");
+	    if (match.equals("documentNode")) {
+		extractMetadataNames(template, doc_meta_names);
+	    } else if (match.equals("classifierNode")) {
+		extractMetadataNames(template, class_meta_names);
+	    }
+	}
+    }
+
+}
+
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/GeneralAction.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/GeneralAction.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/GeneralAction.java	(revision 14125)
@@ -0,0 +1,113 @@
+package org.greenstone.gsdl3.action;
+
+import org.greenstone.gsdl3.core.ModuleInterface;
+import org.greenstone.gsdl3.util.*;
+// XML classes
+import org.w3c.dom.Node; 
+import org.w3c.dom.NodeList; 
+import org.w3c.dom.Document; 
+import org.w3c.dom.Element; 
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Iterator;
+import java.io.File;
+
+
+public class GeneralAction extends Action {
+    
+    /** process a request */
+    public Element process (Element message) {
+
+	// the result
+	Element result = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element page_response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.appendChild(page_response);
+
+	// assume only one request
+	Element request = (Element)GSXML.getChildByTagName(message, GSXML.REQUEST_ELEM);
+
+	// get the param list
+	Element cgi_param_list = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	HashMap params = GSXML.extractParams(cgi_param_list, false);
+	String service_name = (String) params.get(GSParams.SERVICE);
+	String cluster_name = (String) params.get(GSParams.CLUSTER);
+	String response_only_p = (String)params.get(GSParams.RESPONSE_ONLY);
+	boolean response_only = false;
+	if (response_only_p!=null) {
+	    response_only = (response_only_p.equals("1")?true:false);
+	}
+	String request_type = (String) params.get(GSParams.REQUEST_TYPE);
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	String uid = request.getAttribute(GSXML.USER_ID_ATT);
+	// what is carried out depends on the request_type
+	// if rt=d, then a describe request is done,
+	// is rt=r, a request and then a describe request is done
+	// if rt=s, a status request is done.
+
+	// if ro=1, then this calls for a process only page - we do the request
+	// (rt should be r or s) and just give the response straight back
+	// without any page processing
+
+
+	// where to send requests
+	String to;
+	if (cluster_name != null) {
+	    to = GSPath.appendLink(cluster_name, service_name);
+	} else {
+	    to = service_name;
+	}
+
+	if (request_type.equals("r")) {
+	    //do the request
+	    
+	    Element mr_query_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	    Element mr_query_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, lang, uid);
+	    
+	    mr_query_message.appendChild(mr_query_request);
+	    
+	    Element param_list = null;
+	    // add in the service params - except the ones only used by the action
+	    HashMap service_params = (HashMap)params.get("s1");
+	    if (service_params != null) { 
+		param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+		GSXML.addParametersToList(this.doc, param_list, service_params);
+		mr_query_request.appendChild(param_list);
+	    }
+	    
+	    Element mr_query_response = (Element)this.mr.process(mr_query_message);
+	    Element result_response = (Element)GSXML.getChildByTagName(mr_query_response, GSXML.RESPONSE_ELEM);
+	    
+	    if (response_only) {
+		// just send the reponse as is
+		return result_response;
+	    }
+	    if (result_response != null){
+		// else append the contents of the response to the page 
+		GSXML.copyAllChildren(page_response, result_response);
+	    }
+	}
+	
+
+	// another part of the page is the service description
+
+	// request the service info for the selected service - should be cached
+	Element mr_info_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element mr_info_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, to, lang, uid);
+	mr_info_message.appendChild(mr_info_request);
+	Element mr_info_response = (Element) this.mr.process(mr_info_message);
+
+        
+	String path = GSXML.RESPONSE_ELEM;
+	path = GSPath.appendLink(path, GSXML.SERVICE_ELEM);
+	
+
+	Node desNode = GSXML.getNodeByPath(mr_info_response, path);
+	if(desNode != null){
+	    page_response.appendChild((Element)this.doc.importNode(desNode, true));
+	}
+
+	return result;
+    }
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/NoCollQueryAction.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/NoCollQueryAction.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/NoCollQueryAction.java	(revision 14125)
@@ -0,0 +1,219 @@
+package org.greenstone.gsdl3.action;
+
+import org.greenstone.gsdl3.core.ModuleInterface;
+import org.greenstone.gsdl3.util.*;
+// XML classes
+import org.w3c.dom.Node; 
+import org.w3c.dom.NodeList; 
+import org.w3c.dom.Text; 
+import org.w3c.dom.Document; 
+import org.w3c.dom.Element; 
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Vector;
+import java.util.Map;
+import java.util.Iterator;
+import java.io.File;
+
+import org.apache.log4j.*;
+
+/** action class for queries 
+ * this is used when querying isn't collection specific, but it occurs across all collections in the site. The service description is assumed to be known by the xslt so we dont ask for it. we just pass all the service params to the TextQuery service of all the collections */
+public class NoCollQueryAction extends Action {
+    
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.action.NoCollQueryAction.class.getName());
+    /** process - processes a request.
+     */ 
+    public Element process (Element message) {
+
+	// get the request - assume there is only one
+	Element request = (Element)GSXML.getChildByTagName(message, GSXML.REQUEST_ELEM);
+
+	// create the return message
+	Element result = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	// for now we only have one type of query - subaction not used
+	Element response = basicQuery(request);
+	result.appendChild(this.doc.importNode(response, true));
+	return result;
+    }
+    
+    /** a generic query handler 
+     * this gets the service description, does the query (just passes all teh 
+     * params to the service, then gets the titles for any results 
+     */
+    protected Element basicQuery(Element request) {
+	
+	// the result
+	Element page_response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	
+	// extract the params from the cgi-request, and check that we have a coll specified
+	Element cgi_param_list = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	HashMap params = GSXML.extractParams(cgi_param_list, false);
+	
+	String request_type = (String)params.get(GSParams.REQUEST_TYPE);
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	String uid = request.getAttribute(GSXML.USER_ID_ATT);
+	if (request_type.equals("d")) {
+	    // display the query page
+	    // the only info we need to return is the collection list cos the xslt does teh rest
+	    
+	    Element coll_list = getCollectionList(lang, uid);
+	    page_response.appendChild(this.doc.importNode(coll_list, true));
+	    return page_response;
+	    
+	}
+	
+	// else we have a query
+	String service_name = (String)params.get(GSParams.SERVICE);
+	if (service_name == null || service_name.equals("")) {
+	    service_name = "TextQuery";
+	}
+  	String query_coll_list = (String)params.get(GSParams.COLLECTION);
+	
+  	if (query_coll_list == null || query_coll_list.equals("")) {
+  	    logger.error("no collections were specified!");
+  	    Element coll_list = getCollectionList(lang, uid);
+  	    page_response.appendChild(this.doc.importNode(coll_list, true));
+  	    return page_response; 
+  	}
+
+	// service paramList
+	HashMap service_params = (HashMap)params.get("s1");
+	if (service_params == null) { // no query
+	    return page_response;
+	}
+	Element query_param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	GSXML.addParametersToList(this.doc, query_param_list, service_params);
+	
+	// we will do a query for each coll
+	String [] colls = query_coll_list.split(",");
+	
+	Element mr_query_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	
+	for (int i=0; i< colls.length; i++) {
+	    String to = GSPath.appendLink(colls[i], service_name);
+	    Element mr_query_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, lang, uid);
+	    mr_query_message.appendChild(mr_query_request);
+	    mr_query_request.appendChild(query_param_list.cloneNode(true));
+	    
+	}
+	
+	// do the query
+       	Element mr_query_response = (Element)this.mr.process(mr_query_message);
+
+	
+	// get the Title metadata for each node - need Node title and root title
+	Element mr_meta_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	NodeList responses = mr_query_response.getElementsByTagName(GSXML.RESPONSE_ELEM);
+	for (int j=0; j<responses.getLength(); j++) {
+	    Element document_list = (Element)GSXML.getChildByTagName((Element)responses.item(j), GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	    if (document_list != null) {
+		String coll_name = extractCollName(((Element)responses.item(j)).getAttribute(GSXML.FROM_ATT));
+		String path = GSPath.appendLink(coll_name, "DocumentMetadataRetrieve");
+		Element mr_meta_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, path, lang, uid);
+		mr_meta_message.appendChild(mr_meta_request);
+		mr_meta_request.appendChild(this.doc.importNode(document_list, true));
+		// metadata params 
+		Element param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+		Element param = GSXML.createParameter(this.doc, "metadata", "Title");
+		param_list.appendChild(param);
+		param = GSXML.createParameter(this.doc, "metadata", "root_Title");
+		param_list.appendChild(param);
+		mr_meta_request.appendChild(param_list);
+		
+	    }
+	}
+	
+	// do the request
+	Element mr_meta_response = (Element)this.mr.process(mr_meta_message);
+
+	// the result 
+	Element result_doc_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	page_response.appendChild(result_doc_list);
+
+	responses = mr_meta_response.getElementsByTagName(GSXML.RESPONSE_ELEM);
+	for (int j=0; j<responses.getLength(); j++) {
+	    Element document_list = (Element)GSXML.getChildByTagName((Element)responses.item(j), GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	    String coll_name = extractCollName(((Element)responses.item(j)).getAttribute(GSXML.FROM_ATT));
+	    
+	    mergeDocLists(result_doc_list, document_list, coll_name );
+	}
+	
+	
+	return page_response;
+    }
+
+    protected String extractCollName(String path) {
+	return GSPath.removeLastLink(path);
+    }
+
+    protected void mergeDocLists(Element result_list, Element from_list, String collection) {
+
+	Document owner = result_list.getOwnerDocument();
+	Node child = from_list.getFirstChild();
+	while (child != null) {
+	    ((Element)child).setAttribute("collection", collection);
+	    result_list.appendChild(owner.importNode(child, true));
+	    child = child.getNextSibling();
+	}
+	
+    }
+
+
+    protected Element getCollectionList(String lang, String uid) {
+	
+	// first, get the message router info
+	Element coll_list_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element coll_list_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, "", lang, uid);
+	coll_list_message.appendChild(coll_list_request);
+	Element coll_list_response = (Element)this.mr.process(coll_list_message);
+	if (coll_list_response==null) {
+	    logger.error("couldn't query the message router!");
+	    return null;
+	}
+	
+	// second, get the display info for each collection 
+	NodeList colls = coll_list_response.getElementsByTagName(GSXML.COLLECTION_ELEM);
+
+	Element coll_param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	Element param = GSXML.createParameter(this.doc, GSXML.SUBSET_PARAM, GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER); 
+	coll_param_list.appendChild(param);
+	// we will send all the requests in a single message
+	Element metadata_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	for (int i=0; i<colls.getLength(); i++) {
+	    Element c = (Element)colls.item(i);
+	    String name = c.getAttribute(GSXML.NAME_ATT);	    
+	    
+	    Element metadata_request = GSXML.createBasicRequest(this.doc,  GSXML.REQUEST_TYPE_DESCRIBE, name, lang, uid);
+	    metadata_request.appendChild(coll_param_list.cloneNode(true));
+	    metadata_message.appendChild(metadata_request);
+	}
+	
+	Element metadata_response = (Element)this.mr.process(metadata_message);
+	
+	NodeList coll_responses = metadata_response.getElementsByTagName(GSXML.RESPONSE_ELEM);
+	// check that have same number of responses as collections
+	if (colls.getLength() != coll_responses.getLength()) {
+	    logger.error("didn't get a response for each collection - somethings gone wrong!");
+	    // for now, dont use the metadata
+	} else {
+	    for (int i=0; i<colls.getLength(); i++) {
+		Element c1 = (Element)colls.item(i);
+		Element c2 = (Element)coll_responses.item(i);
+		if (c1.getAttribute(GSXML.NAME_ATT).equals(c2.getAttribute(GSXML.FROM_ATT))) {
+		    //add the collection data into the original response
+		    GSXML.mergeElements(c1, (Element)GSXML.getChildByTagName(c2, GSXML.COLLECTION_ELEM));
+		} else {
+		    logger.error("response does not correspond to request!");
+		} 
+		
+	    }
+	}
+
+	String path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER);
+	Element response = (Element) GSXML.getNodeByPath(coll_list_response, path);
+	return response;
+
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/PageAction.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/PageAction.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/PageAction.java	(revision 14125)
@@ -0,0 +1,220 @@
+package org.greenstone.gsdl3.action;
+
+import org.greenstone.gsdl3.core.ModuleInterface;
+import org.greenstone.gsdl3.util.*;
+// XML classes
+import org.w3c.dom.Node; 
+import org.w3c.dom.NodeList; 
+import org.w3c.dom.Document; 
+import org.w3c.dom.Element;
+
+import java.util.HashMap;
+import java.io.File;
+
+import org.apache.log4j.*;
+
+public class PageAction extends Action {
+   
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.action.PageAction.class.getName());
+
+    public static final String HOME_PAGE = "home";
+    public static final String ABOUT_PAGE = "about";
+    public static final String PREFS_PAGE = "pref";
+    public Element process (Element message) {
+	
+	Element request = (Element) GSXML.getChildByTagName(message, GSXML.REQUEST_ELEM);
+	// the page name is the subaction
+	String page_name = request.getAttribute(GSXML.SUBACTION_ATT);
+	if (page_name.equals("")) { // if no page specified, assume home page
+	    page_name = HOME_PAGE;
+	}
+	Element result = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element response;
+	if (page_name.equals(HOME_PAGE)) {
+	    response = homePage(request);
+	} else if (page_name.equals(ABOUT_PAGE)) {
+	    response = aboutPage(request);
+//  	} else if (page_name.equals(PREFS_PAGE)) {
+//  	    response = prefsPage(request);
+	} else { // unknown page
+	    
+	    logger.error("unknown page specified!");
+	    response =  unknownPage(request);
+	}
+	
+	result.appendChild(this.doc.importNode(response, true));
+	logger.debug("page action result: "+this.converter.getPrettyString(result));
+	return result;
+    }
+
+
+    protected Element homePage(Element request) {
+	
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	String uid = request.getAttribute(GSXML.USER_ID_ATT);
+	// first, get the message router info
+	Element info_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element coll_list_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, "", lang, uid);
+	info_message.appendChild(coll_list_request);
+	Element info_response_message = (Element)this.mr.process(info_message);
+	if (info_response_message==null) {
+	    logger.error(" couldn't query the message router!");
+	    return null;
+	}
+	Element info_response = (Element)GSXML.getChildByTagName(info_response_message, GSXML.RESPONSE_ELEM);
+	if (info_response==null) {
+	    logger.error("couldn't query the message router!");
+	    return null;
+	}
+	    
+	// second, get the metadata for each collection - we only want specific
+	// elements but for now, we'll just get it all
+	Element collection_list = (Element)GSXML.getChildByTagName(info_response, GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER);
+	logger.info(GSXML.xmlNodeToString(collection_list));
+        if (collection_list != null) {
+	    NodeList colls = GSXML.getChildrenByTagName(collection_list, GSXML.COLLECTION_ELEM);
+	    if (colls.getLength()>0) {
+		sendMultipleRequests(colls, null, GSXML.REQUEST_TYPE_DESCRIBE, lang, uid);
+	    }
+	}
+
+	// get metadata for any services
+	Element service_list = (Element)GSXML.getChildByTagName(info_response, GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER);
+	if (service_list != null) {
+	    NodeList services = GSXML.getChildrenByTagName(service_list, GSXML.SERVICE_ELEM);
+	    if (services.getLength() > 0) {
+		sendMultipleRequests(services, null, GSXML.REQUEST_TYPE_DESCRIBE, lang, uid);
+	    }
+	}
+
+	// get metadata for service clusters
+	Element cluster_list = (Element)GSXML.getChildByTagName(info_response, GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER);
+	if (cluster_list != null) {
+	    NodeList clusters = GSXML.getChildrenByTagName(cluster_list, GSXML.CLUSTER_ELEM);
+	    if (clusters.getLength() > 0) {
+		sendMultipleRequests(clusters, null, GSXML.REQUEST_TYPE_DESCRIBE, lang, uid);
+		
+	    }
+	}
+	
+	// all the components have been merged into info_response
+	return info_response;
+	
+    } // homePage
+
+    protected Element aboutPage(Element request) {
+
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	String uid = request.getAttribute(GSXML.USER_ID_ATT);
+	// extract the params from the cgi-request, 
+	Element cgi_paramList = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	HashMap params = GSXML.extractParams(cgi_paramList, false);
+	
+	String coll_name = (String)params.get(GSParams.COLLECTION);
+	if (coll_name == null || coll_name.equals("")) {
+	    logger.error("about page requested with no collection or cluster specified!");
+	    // return an empty response
+	    return this.doc.createElement(GSXML.RESPONSE_ELEM);
+	}
+	
+	// get the collection or cluster description
+	Element coll_about_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	
+	Element coll_about_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE,  coll_name, lang, uid);
+	coll_about_message.appendChild(coll_about_request);
+	
+	Element coll_about_response = (Element)this.mr.process(coll_about_message);
+
+	if (coll_about_response == null) {
+	    return null;
+	}
+	
+	// second, get the info for each service - we only want display items 
+	// but for now, we'll just get it all
+	NodeList services = coll_about_response.getElementsByTagName(GSXML.SERVICE_ELEM);
+	if (services.getLength() > 0) {
+	    sendMultipleRequests(services, coll_name, GSXML.REQUEST_TYPE_DESCRIBE, lang, uid);
+	}
+	
+	Element response = (Element) GSXML.getChildByTagName(coll_about_response, GSXML.RESPONSE_ELEM);
+	return response;
+    }
+
+//      protected Element prefsPage(Element request) {
+
+//  	return null;
+//      }
+
+    /** if we dont know the page type, use this method */
+    protected Element unknownPage(Element request) {
+	
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	String uid = request.getAttribute(GSXML.USER_ID_ATT);
+	String page_name = request.getAttribute(GSXML.SUBACTION_ATT);
+
+	// extract the params from the cgi-request, 
+	Element cgi_paramList = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	HashMap params = GSXML.extractParams(cgi_paramList, false);
+	
+	String coll_name = (String)params.get(GSParams.COLLECTION);
+	if (coll_name == null || coll_name.equals("")) {
+	    // just return an empty response
+	    return this.doc.createElement(GSXML.RESPONSE_ELEM);
+	}
+	
+	// else get the coll description - actually this is the same as for the about page - should we merge these two methods??
+	
+	// if there is a service specified should we get the service description instead??
+	// get the collection or cluster description
+	Element coll_about_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	
+	Element coll_about_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE,  coll_name, lang, uid);
+	coll_about_message.appendChild(coll_about_request);
+	
+	Element coll_about_response = (Element)this.mr.process(coll_about_message);
+
+	Element response = (Element) GSXML.getChildByTagName(coll_about_response, GSXML.RESPONSE_ELEM);
+	return response;
+	
+    }
+
+
+    protected boolean sendMultipleRequests(NodeList items, String path_prefix, String request_type, String lang, String uid) {
+
+	// we will send all the requests in a single message
+	Element message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	for (int i=0; i<items.getLength(); i++) {
+	    Element c = (Element)items.item(i);
+	    String path = c.getAttribute(GSXML.NAME_ATT);	    
+	    if (path_prefix != null) {
+		path = GSPath.appendLink(path_prefix, path);
+	    }
+	    Element request = GSXML.createBasicRequest(this.doc, request_type, path, lang, uid);
+	    message.appendChild(request);
+	}
+	
+	Element response_message = (Element)this.mr.process(message);
+	    
+	NodeList responses = response_message.getElementsByTagName(GSXML.RESPONSE_ELEM);
+	// check that have same number of responses as requests
+	if (items.getLength() != responses.getLength()) {
+	    logger.error("didn't get a response for each request - somethings gone wrong!");
+	    return false;
+	} 
+	
+	for (int i=0; i<items.getLength(); i++) {
+	    Element c1 = (Element)items.item(i);
+	    Element c2 = (Element)GSXML.getChildByTagName((Element)responses.item(i), c1.getTagName());
+    	    if (c1 != null && c2 !=null && c1.getAttribute(GSXML.NAME_ATT).endsWith(c2.getAttribute(GSXML.NAME_ATT))) {
+		//add the new data into the original element
+		GSXML.mergeElements(c1, c2);
+	    } else {
+		logger.error(" response does not correspond to request!");
+	    } 
+	    
+	}
+	
+	return true;
+    
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/ProcessAction.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/ProcessAction.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/ProcessAction.java	(revision 14125)
@@ -0,0 +1,137 @@
+package org.greenstone.gsdl3.action;
+
+import org.greenstone.gsdl3.core.ModuleInterface;
+import org.greenstone.gsdl3.util.*;
+// XML classes
+import org.w3c.dom.Node; 
+import org.w3c.dom.NodeList; 
+import org.w3c.dom.Document; 
+import org.w3c.dom.Element; 
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Iterator;
+import java.io.File;
+
+public class ProcessAction extends Action {
+    
+    /** process a request */
+    public Element process (Element message) {
+
+	// the result
+	Element result = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element page_response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.appendChild(page_response);
+
+	// assume only one request
+	Element request = (Element)GSXML.getChildByTagName(message, GSXML.REQUEST_ELEM);
+
+	// get the param list
+	Element cgi_param_list = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	HashMap params = GSXML.extractParams(cgi_param_list, false);
+	String service_name = (String) params.get(GSParams.SERVICE);
+	String cluster_name = (String) params.get(GSParams.CLUSTER);
+	String response_only_p = (String)params.get(GSParams.RESPONSE_ONLY);
+	boolean response_only = false;
+	if (response_only_p!=null) {
+	    response_only = (response_only_p.equals("1")?true:false);
+	}
+	String request_type = (String) params.get(GSParams.REQUEST_TYPE);
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	String uid = request.getAttribute(GSXML.USER_ID_ATT);
+	// what is carried out depends on the request_type
+	// if rt=d, then a describe request is done,
+	// is rt=r, a request and then a describe request is done
+	// if rt=s, a status request is done.
+
+	// if ro=1, then this calls for a process only page - we do the request
+	// (rt should be r or s) and just give the response straight back
+	// without any page processing
+
+
+	// where to send requests
+	String to;
+	if (cluster_name != null) {
+	    
+	    to = GSPath.appendLink(cluster_name, service_name);
+	} else {
+	    to = service_name;
+	}
+
+	if (!request_type.equals("d")) {
+	    // if rt=s or rt=r, do the request
+	    
+	    Element mr_query_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	    String request_type_att;
+	    Element param_list = null;
+	    if (request_type.equals("s")) { // status
+		request_type_att = GSXML.REQUEST_TYPE_STATUS;
+		param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+		Element param = this.doc.createElement(GSXML.PARAM_ELEM);
+		param.setAttribute(GSXML.NAME_ATT, GSParams.PROCESS_ID);
+		param.setAttribute(GSXML.VALUE_ATT, (String)params.get(GSParams.PROCESS_ID));
+		param_list.appendChild(param);
+	    } else {
+		request_type_att = GSXML.REQUEST_TYPE_PROCESS;
+		// add in the service params - except the ones only used by the action
+		HashMap service_params = (HashMap)params.get("s1");
+		if (service_params != null) { 
+		    param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+		    GSXML.addParametersToList(this.doc, param_list, service_params);
+		}
+		
+	    }
+	    Element mr_query_request = GSXML.createBasicRequest(this.doc, request_type_att, to, lang, uid);
+	    if (param_list != null) {
+		mr_query_request.appendChild(param_list);
+	    }
+	    mr_query_message.appendChild(mr_query_request);
+	    
+	    Element mr_query_response = (Element)this.mr.process(mr_query_message);
+	    Element result_response = (Element)GSXML.getChildByTagName(mr_query_response, GSXML.RESPONSE_ELEM);
+	    
+	    if (response_only) {
+		// just send the reponse as is
+		return result_response;
+	    }
+	    
+	    // else append the contents of the response to the page - just the status elem for now
+	    Element status = (Element)GSXML.getChildByTagName(result_response, GSXML.STATUS_ELEM);
+	    page_response.appendChild(this.doc.importNode(status, true));
+	}
+	
+
+	// another part of the page is the service description
+
+	// request the service info for the selected service - should be cached
+	Element mr_info_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element mr_info_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, to, lang, uid);
+	mr_info_message.appendChild(mr_info_request);
+	Element mr_info_response = (Element) this.mr.process(mr_info_message);
+
+	String path = GSXML.RESPONSE_ELEM;
+	path = GSPath.appendLink(path, GSXML.SERVICE_ELEM);
+	Element description = (Element)this.doc.importNode(GSXML.getNodeByPath(mr_info_response, path), true);
+
+	page_response.appendChild(description);
+
+	return result;
+    }
+
+    protected Element getServiceParamList(Element cgi_param_list) {
+
+	Element new_param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	Element param;
+	NodeList cgi_params = cgi_param_list.getChildNodes();
+	for (int i=0; i<cgi_params.getLength(); i++) {
+	    Element p = (Element) cgi_params.item(i);
+	    String name = p.getAttribute(GSXML.NAME_ATT);
+	    if (name.equals(GSParams.SERVICE) || name.equals(GSParams.REQUEST_TYPE) || name.equals(GSParams.CLUSTER)) {
+		continue;
+	    }
+	    // else add it in to the list
+	    new_param_list.appendChild(this.doc.importNode(p, true));
+	}
+	return new_param_list;
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/QueryAction.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/QueryAction.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/QueryAction.java	(revision 14125)
@@ -0,0 +1,267 @@
+package org.greenstone.gsdl3.action;
+
+import org.greenstone.gsdl3.core.ModuleInterface;
+import org.greenstone.gsdl3.util.*;
+// XML classes
+import org.w3c.dom.Node; 
+import org.w3c.dom.NodeList; 
+import org.w3c.dom.Text; 
+import org.w3c.dom.Document; 
+import org.w3c.dom.Element; 
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Vector;
+import java.util.Map;
+import java.util.Iterator;
+import java.io.File;
+
+import org.apache.log4j.*;
+
+/** action class for queries */
+public class QueryAction extends Action {
+
+
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.action.QueryAction.class.getName());
+    
+    /** process - processes a request.
+     */ 
+    public Element process (Element message) {
+
+	// get the request - assume there is only one
+	Element request = (Element)GSXML.getChildByTagName(message, GSXML.REQUEST_ELEM);
+
+	// create the return message
+	Element result = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element response = basicQuery(request);
+	result.appendChild(this.doc.importNode(response, true));
+	return result;
+    }
+    
+    /** a generic query handler 
+     * this gets the service description, does the query (just passes all the 
+     * params to the service, then gets the titles for any results 
+     */
+    protected Element basicQuery(Element request) {
+	
+	// the result
+	Element page_response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	
+	// extract the params from the cgi-request, and check that we have a coll specified
+	Element cgi_param_list = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	HashMap params = GSXML.extractParams(cgi_param_list, false);
+	
+	String request_type = (String)params.get(GSParams.REQUEST_TYPE);
+	String service_name = (String)params.get(GSParams.SERVICE);
+	String collection = (String)params.get(GSParams.COLLECTION);
+
+	// collection may be null or empty when we are doing cross coll services
+	if (collection == null || collection.equals("")) {
+	    collection = null;
+	}
+	
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	String uid = request.getAttribute(GSXML.USER_ID_ATT);
+	String to = service_name;
+	if (collection != null) {
+	    to = GSPath.prependLink(to, collection);
+	}
+	
+	if (request_type.indexOf("d")!=-1) {
+	    // we have been asked for the service description
+	    Element mr_info_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	    Element mr_info_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE,  to, lang, uid);
+	    mr_info_message.appendChild(mr_info_request);
+	    
+	    // process the message
+	    Element mr_info_response = (Element) this.mr.process(mr_info_message);
+	    // the response
+	    Element service_response = (Element)GSXML.getChildByTagName(mr_info_response, GSXML.RESPONSE_ELEM);
+	    
+	    Element service_description = (Element)this.doc.importNode(GSXML.getChildByTagName(service_response, GSXML.SERVICE_ELEM), true);
+	    page_response.appendChild(service_description);
+	}
+	
+	if (request_type.indexOf("r") == -1) {
+	    // just a display request, no actual processing to do
+	    return page_response;
+	}
+	
+	// check that we have some service params
+	HashMap service_params = (HashMap)params.get("s1");
+	if (service_params == null) { // no query
+	    return page_response;
+	}
+
+	// create the query request
+	Element mr_query_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element mr_query_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, lang, uid);
+	mr_query_message.appendChild(mr_query_request);
+	
+	Element query_param_list = this.doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
+	GSXML.addParametersToList(this.doc, query_param_list, service_params);
+	mr_query_request.appendChild(query_param_list);
+	
+	// also get the format stuff now if there is some
+	Element format_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_FORMAT, to, lang, uid);
+	mr_query_message.appendChild(format_request);
+
+	// do the query
+       	Element mr_query_response = (Element)this.mr.process(mr_query_message);
+
+	// check for errors
+	if (processErrorElements(mr_query_response, page_response)) {
+	    return page_response;
+	}
+	
+	NodeList responses = mr_query_response.getElementsByTagName(GSXML.RESPONSE_ELEM);
+	Element query_response = (Element) responses.item(0);
+	Element format_response = (Element) responses.item(1);
+	
+	Element query_result_metadata_list = (Element) GSXML.getChildByTagName(query_response, GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+	if (query_result_metadata_list == null) {
+	    logger.error("No query result metadata.\n");
+	} else { // add it into the page response
+	    page_response.appendChild(this.doc.importNode(query_result_metadata_list, true)); 
+	}
+	
+	Element query_term_info_list = (Element) GSXML.getChildByTagName(query_response, GSXML.TERM_ELEM+GSXML.LIST_MODIFIER);
+	if (query_term_info_list == null) {
+	    logger.error("No query term information.\n");
+	} else { // add it into the page response
+	    page_response.appendChild(this.doc.importNode(query_term_info_list, true));
+	}
+	
+	// check that there are some documents - for now check the list, but later should use a numdocs metadata elem	
+	Element document_list = (Element)GSXML.getChildByTagName(query_response, GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	// documentList not present if no docs found
+	if (document_list == null) {
+	    // add in a dummy doc node list - used by the display. need to think about this
+	    page_response.appendChild(this.doc.createElement(GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER));
+	    return page_response;
+	}
+
+	// now we check to see if there is metadata already - some search services return predefined metadata. if there is some, don't do a metadata request
+	NodeList doc_metadata = document_list.getElementsByTagName(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+	if (doc_metadata.getLength()>0) {
+	    logger.error("have already found metadata!");
+	    // append the doc list to the result
+	    page_response.appendChild(this.doc.importNode(document_list, true));
+	    return page_response;
+	}
+	
+	// get the metadata elements needed from the format statement if any
+	HashSet metadata_names = new HashSet();
+	metadata_names.add("Title");
+	// add in the format info to the stylesheet if there is any
+	Element format_elem = (Element)GSXML.getChildByTagName(format_response, GSXML.FORMAT_ELEM);
+	if (format_elem != null) {
+	    // set the format type
+	    format_elem.setAttribute(GSXML.TYPE_ATT, "search");
+	    // for now just add to the response
+	    page_response.appendChild(this.doc.importNode(format_elem, true));
+	    extractMetadataNames(format_elem, metadata_names);
+	} 
+	
+	// paging of the results is done here - we filter the list to remove unwanted entries before retrieving metadata
+	Element filtered_doc_list = filterDocList(params, service_params, document_list);
+	
+	// do the metadata request on the filtered list
+	Element mr_metadata_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	to = "DocumentMetadataRetrieve";
+	if (collection != null) {
+	    to = GSPath.prependLink(to, collection);
+	}
+	Element mr_metadata_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, lang, uid);
+	mr_metadata_message.appendChild(mr_metadata_request);
+	
+	// just get all for now - the receptionist should perhaps pass in some
+	// metadata that it wants, and QueryAction should look through the format stuff to see if there is any other?
+	
+	Element dm_param_list  = createMetadataParamList(metadata_names);
+	
+	mr_metadata_request.appendChild(dm_param_list);
+	
+	// add in the doc node list too
+	mr_metadata_request.appendChild(filtered_doc_list);
+
+	Element mr_metadata_response = (Element) this.mr.process(mr_metadata_message);	
+	// check for errors
+	processErrorElements(mr_metadata_response, page_response);
+	
+	Element metadata_response = (Element) GSXML.getChildByTagName(mr_metadata_response, GSXML.RESPONSE_ELEM);
+
+	Element query_result_document_list = (Element) GSXML.getChildByTagName(metadata_response, GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	
+	if (query_result_document_list != null) {
+	    page_response.appendChild(this.doc.importNode(query_result_document_list, true));
+	}
+	
+	logger.debug("Query page:\n" + this.converter.getPrettyString(page_response));
+	return page_response;
+    }
+
+    /** this filters out some of the doc results for result paging */
+    protected Element filterDocList(HashMap params, HashMap service_params, Element orig_doc_list) {
+	
+	// check the hits_per_page param - is it a service param??
+	String hits_pp = (String) service_params.get("hitsPerPage");
+	if (hits_pp != null) {
+	    // the service is doing the paging, so we want to display all of the returned docs
+	    return (Element)this.doc.importNode(orig_doc_list, true);
+	}
+	
+	hits_pp = (String)params.get("hitsPerPage");
+	int hits = 20;
+	if (hits_pp != null && !hits_pp.equals("")) {
+	    try {
+		hits = Integer.parseInt(hits_pp);
+	    } catch (Exception e) {
+		hits=20;
+	    }
+	}
+
+	if (hits == -1) { // all
+	    return (Element)this.doc.importNode(orig_doc_list, true);
+	}
+	NodeList result_docs = orig_doc_list.getElementsByTagName(GSXML.DOC_NODE_ELEM);
+	
+	int num_docs = result_docs.getLength();
+	if (num_docs <= hits) {
+	    // too few docs to do paging
+	    return (Element)this.doc.importNode(orig_doc_list, true);
+	}
+
+	// now we need our own doc list
+	Element result_list = this.doc.createElement(GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
+	String start_p = (String)params.get("startPage");
+	int start = 1;
+	if (start_p != null && !start_p.equals("")) {
+	    try {
+		start = Integer.parseInt(start_p);
+	    } catch (Exception e) {
+		start = 1;
+	    }
+	}
+
+	int start_from = (start-1)*hits;
+	int end_at = (start*hits)-1;
+
+	if (start_from > num_docs) {
+	    // something has gone wrong
+	    return result_list;
+	}
+	
+	if (end_at > num_docs) {
+	    end_at = num_docs-1;
+	}
+
+	// now we finally have the docs numbers to use
+	for (int i=start_from; i<=end_at; i++) {
+	    result_list.appendChild(this.doc.importNode(result_docs.item(i), true));
+	}
+
+	return result_list;
+    }
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/SystemAction.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/SystemAction.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/SystemAction.java	(revision 14125)
@@ -0,0 +1,86 @@
+package org.greenstone.gsdl3.action;
+
+import org.greenstone.gsdl3.core.ModuleInterface;
+import org.greenstone.gsdl3.util.*;
+
+// XML classes
+import org.w3c.dom.Node; 
+import org.w3c.dom.Element; 
+import org.w3c.dom.Document; 
+
+// other java stuff
+import java.io.File;
+import java.util.HashMap;
+
+import org.apache.log4j.*;
+
+public class SystemAction extends Action {
+    
+      static Logger logger = Logger.getLogger(org.greenstone.gsdl3.action.SystemAction.class.getName());
+
+    /** process a request */
+    public Element process (Element message) {
+	
+	// assume only one request
+	Element request = (Element)GSXML.getChildByTagName(message, GSXML.REQUEST_ELEM);
+	
+	String subaction = request.getAttribute(GSXML.SUBACTION_ATT);
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	String uid = request.getAttribute(GSXML.USER_ID_ATT);
+	// get the param list
+	Element cgi_param_list = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	HashMap params = GSXML.extractParams(cgi_param_list, false);
+
+	Element result = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	
+	String coll = (String)params.get(GSParams.SYSTEM_CLUSTER);
+
+	String to = "";
+	if (coll!=null && !coll.equals("")) {
+	    to = coll;
+	}
+
+	Element mr_request_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element mr_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_SYSTEM, to, lang, uid);
+	mr_request_message.appendChild(mr_request);
+	
+	Element system = this.doc.createElement(GSXML.SYSTEM_ELEM);
+	mr_request.appendChild(system);
+	
+	// will need to change the following if can do more than one system request at once
+	if (subaction.equals("c")) { // configure
+	    system.setAttribute(GSXML.TYPE_ATT, GSXML.SYSTEM_TYPE_CONFIGURE);
+	    String info = (String)params.get(GSParams.SYSTEM_SUBSET);
+	    system.setAttribute(GSXML.SYSTEM_SUBSET_ATT, info);
+	
+	} else {
+	    String name = (String)params.get(GSParams.SYSTEM_MODULE_NAME);
+	    String type = (String)params.get(GSParams.SYSTEM_MODULE_TYPE);
+
+	    system.setAttribute(GSXML.SYSTEM_MODULE_NAME_ATT, name);
+	    system.setAttribute(GSXML.SYSTEM_MODULE_TYPE_ATT, type);
+	    
+	    if (subaction.equals("d")) { // delete
+		system.setAttribute(GSXML.TYPE_ATT, GSXML.SYSTEM_TYPE_DEACTIVATE);
+
+	    } else if (subaction.equals("a")) { // add
+		system.setAttribute(GSXML.TYPE_ATT, GSXML.SYSTEM_TYPE_ACTIVATE);
+	    } else {
+	    // create the default response
+	    // for now just have an error
+	    logger.error("bad subaction type");
+	    Element page_response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	    result.appendChild(page_response);
+	
+	    return result;
+	    }
+	}
+
+	Element response_message = this.mr.process(mr_request_message);
+	
+	result.appendChild(GSXML.duplicateWithNewName(this.doc, (Element)GSXML.getChildByTagName(response_message, GSXML.RESPONSE_ELEM), GSXML.RESPONSE_ELEM, true));
+	return result;
+	
+    }
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/XMLDocumentAction.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/XMLDocumentAction.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/action/XMLDocumentAction.java	(revision 14125)
@@ -0,0 +1,106 @@
+package org.greenstone.gsdl3.action;
+
+import org.greenstone.gsdl3.core.ModuleInterface;
+import org.greenstone.gsdl3.util.*;
+import org.greenstone.gsdl3.service.TEIRetrieve;
+// XML classes
+import org.w3c.dom.Node; 
+import org.w3c.dom.NodeList; 
+import org.w3c.dom.Text; 
+import org.w3c.dom.Document; 
+import org.w3c.dom.Element; 
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Vector;
+import java.util.Map;
+import java.util.Iterator;
+import java.io.File;
+
+/** action class for retrieving parts of XML documents */
+public class XMLDocumentAction extends Action {
+    
+   
+    /** process - processes a request.
+     */ 
+    public Element process (Element message) {
+	
+	// get the request - assume there is only one
+	Element request = (Element)GSXML.getChildByTagName(message, GSXML.REQUEST_ELEM);
+
+	// create the return message
+	Element result = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element page_response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.appendChild(page_response);
+	
+	// extract the params from the cgi-request, and check that we have a coll specified
+	Element cgi_param_list = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	HashMap params = GSXML.extractParams(cgi_param_list, false);
+
+	String collection = (String)params.get(GSParams.COLLECTION);
+	if (collection == null || collection.equals("")) {
+	    return result;
+	}
+	String doc_name = (String) params.get(GSParams.DOCUMENT);
+	if (doc_name == null || doc_name.equals("")) {
+	    return result;
+	}
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	String uid = request.getAttribute(GSXML.USER_ID_ATT);
+	
+	// subaction used to decide if we are returning content or structure
+	String document_mode = request.getAttribute(GSXML.SUBACTION_ATT);
+	String to = null;
+	if (document_mode.equals("text")) {
+	    to = GSPath.appendLink(collection, "DocumentContentRetrieve");
+	} else if (document_mode.equals("toc")) {
+	    to = GSPath.appendLink(collection, "DocumentStructureRetrieve");
+	} else { // the default is text
+	    to = GSPath.appendLink(collection, "DocumentContentRetrieve");
+	}
+	
+	// make the request to the collection
+	Element mr_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	
+	Element ret_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, lang, uid);
+	mr_message.appendChild(ret_request);
+
+	Element doc_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	ret_request.appendChild(doc_list);
+	Element doc = this.doc.createElement(GSXML.DOC_NODE_ELEM);
+	doc.setAttribute(GSXML.NODE_ID_ATT, doc_name);
+	doc_list.appendChild(doc);
+	
+	// also add in a request for the Title metadata
+	to = GSPath.appendLink(collection, "DocumentMetadataRetrieve");
+	Element meta_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, lang, uid);
+	// copy the doc list
+	meta_request.appendChild(doc_list.cloneNode(true));
+	// add in a metadata param
+	Element param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	meta_request.appendChild(param_list);
+	Element param = GSXML.createParameter(this.doc, "metadata", "root_Title");
+	param_list.appendChild(param);
+	
+	// add the request to the message
+	mr_message.appendChild(meta_request);
+	
+	Element ret_response = this.mr.process(mr_message);
+	String [] links = {GSXML.RESPONSE_ELEM, GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER, GSXML.DOC_NODE_ELEM};
+	String path = GSPath.createPath(links);
+	Element doc_node = (Element)this.doc.importNode(GSXML.getNodeByPath(ret_response, path), true);
+	page_response.appendChild(doc_node);
+
+	// get the metadata list
+	Element meta_response = (Element)ret_response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(1);
+	String [] mlinks  = {GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER, GSXML.DOC_NODE_ELEM, GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER};
+	path = GSPath.createPath(mlinks);
+	
+	Element meta_list = (Element)GSXML.getNodeByPath(meta_response, path);
+	if (meta_list != null) {
+	    doc_node.appendChild(this.doc.importNode(meta_list, true));
+	}
+	return result;
+    }
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/build/CollectionConstructor.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/build/CollectionConstructor.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/build/CollectionConstructor.java	(revision 14125)
@@ -0,0 +1,97 @@
+package org.greenstone.gsdl3.build;
+
+import org.greenstone.gsdl3.util.*;
+//import java.util.Thread
+import javax.swing.event.EventListenerList;
+import org.w3c.dom.Element;
+
+/** base class for collection construction */
+public abstract class CollectionConstructor 
+    extends Thread {
+
+    /** the site in which building is to take place */
+    protected String site_home = null;
+    /** the name of the collection */
+    protected String collection_name = null;
+    /** the stage of construction */
+    protected int process_type = -1;
+    /** other arguments/parameters for the construction process - in a paramList */
+    protected Element process_params = null;
+    /** the list of listeners for the process */
+    protected EventListenerList listeners = null;
+    /** A flag used to determine if this process has been asked to cancel. */
+    protected boolean cancel = false;
+    
+    public CollectionConstructor(String name) {
+	super(name);
+	this.listeners = new EventListenerList();
+    }
+	
+    /** carry out any set up stuff - returns false if couldn't set up properly
+     */
+    public boolean configure() {
+	return true;
+    }
+    public void stopAction() {
+	this.cancel = true;
+    }
+    
+    public void setActionType(int type) {
+	this.process_type = type;
+    }
+    public void setSiteHome(String site_home) {
+	this.site_home = site_home;
+    }
+    public void setCollectionName(String coll_name) {
+	this.collection_name = coll_name;
+    }
+    public void setProcessParams(Element params) {
+	this.process_params = params;
+    }
+    public boolean addListener(ConstructionListener listener) {
+	this.listeners.add(ConstructionListener.class, listener);
+	return true;
+    }
+    public boolean removeListener(ConstructionListener listener) {
+	this.listeners.remove(ConstructionListener.class, listener);
+	return true;
+    }
+
+    protected void sendProcessBegun(ConstructionEvent evt) {
+	Object[] concerned = this.listeners.getListenerList();
+	for(int i = 0; i < concerned.length ; i+=2) {
+	    if(concerned[i] == ConstructionListener.class) {
+		((ConstructionListener)concerned[i+1]).processBegun(evt);
+	    }
+	}
+    }
+    protected void sendProcessComplete(ConstructionEvent evt) {
+	Object[] concerned = this.listeners.getListenerList();
+	for(int i = 0; i < concerned.length ; i+=2) {
+	    if(concerned[i] == ConstructionListener.class) {
+		((ConstructionListener)concerned[i+1]).processComplete(evt);
+	    }
+	}
+    }
+    
+    protected void sendProcessStatus(ConstructionEvent evt) {
+
+	Object[] concerned = this.listeners.getListenerList();
+	for(int i = 0; i < concerned.length ; i+=2) {
+	    if(concerned[i] == ConstructionListener.class) {
+		((ConstructionListener)concerned[i+1]).processStatus(evt);
+	    }
+	}
+    }
+    protected void sendMessage(ConstructionEvent evt) {
+
+	Object[] concerned = this.listeners.getListenerList();
+	for(int i = 0; i < concerned.length ; i+=2) {
+	    if(concerned[i] == ConstructionListener.class) {
+		((ConstructionListener)concerned[i+1]).message(evt);
+	    }
+	}
+    }
+    
+    abstract public void run();
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/build/ConstructCollection.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/build/ConstructCollection.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/build/ConstructCollection.java	(revision 14125)
@@ -0,0 +1,140 @@
+package org.greenstone.gsdl3.build;
+import org.greenstone.gsdl3.util.*;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Document;
+import java.io.File;
+
+/** the class containing the main program for collection building - is essentially a wrapper around a CollectionConstructor
+ * @see CollectionConstructor
+ */
+public class ConstructCollection 
+    implements ConstructionListener {
+    
+    static public void main(String [] args) {
+
+	String site_home = null;
+	String coll_name = null;
+	int process_mode = -1;
+	if (args.length < 4) {
+	    printUsage();
+	    return;
+	}
+
+	// parse the args
+
+	XMLConverter converter = new XMLConverter();
+	Document doc = converter.newDOM();
+	Element option_list = doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	Element option;
+
+	for (int i=0; i<args.length-1; i++) {
+	    String key = args[i];
+	    if (!key.startsWith("-")) {
+		continue; // ignore options that dont start with '-'
+	    }
+	    key = key.substring(1);
+	    String val = args[i+1];
+	    if (val.startsWith("-")) {
+		val=null;
+	    } else {
+		i++;
+	    }
+	    
+	    if (key.equals("site")) {
+		site_home = val;
+	    } else if (key.equals("mode")) {
+		if (val==null) {
+		    continue;
+		}
+		if (val.equals("new")) {
+		    process_mode = GS2PerlConstructor.NEW;
+		} else if (val.equals("import")) {
+		    process_mode = GS2PerlConstructor.IMPORT;
+		} else if (val.equals("build")) {
+		    process_mode = GS2PerlConstructor.BUILD;
+		} else if (val.equals("activate")) {
+		    process_mode = GS2PerlConstructor.ACTIVATE;
+		}
+
+	    } else { // an option to pass to the builder
+ 		option = doc.createElement(GSXML.PARAM_ELEM);
+		option.setAttribute(GSXML.NAME_ATT, key);
+		if (val!=null) {
+		    option.setAttribute(GSXML.VALUE_ATT, val);
+		}
+		option_list.appendChild(option);
+	    }
+	}
+	String last_arg = args[args.length-1];
+	if (last_arg.startsWith("-")) { // should be coll name
+	    System.out.println("ERROR: the last arg should be the collection name!");
+	    printUsage();
+	    return;
+	}
+	
+	coll_name = last_arg;
+	
+	// check that we have the required fields
+	if (site_home==null || process_mode == -1 || coll_name==null) {
+	    System.out.println("ERROR: you have not specified all the necessary args!");
+	    printUsage();
+	    return;
+	}
+
+	// check that the collection name is valid - ie the directory exists if this is not a new one, or doesn't exist if we are creating a new one
+	File coll_dir = new File(GSFile.collectionBaseDir(site_home, coll_name));
+	if (process_mode != GS2PerlConstructor.NEW && !coll_dir.exists()) {
+	    System.out.println("ERROR: Invalid collection ("+coll_name+").");
+	    printUsage();
+	    return;
+	} else if (process_mode == GS2PerlConstructor.NEW && 
+		   coll_dir.exists()) {
+	    System.out.println("ERROR: there is already a collection named "+coll_name);
+	    printUsage();
+	    return;
+	}
+	
+   
+	ConstructCollection processor = new ConstructCollection();
+	GS2PerlConstructor constructor = new GS2PerlConstructor("perl_build");
+	if (!constructor.configure()) {
+	    System.out.println("couldn't configure the constructor!!");
+	    return;
+	}
+	constructor.setCollectionName(coll_name);
+	constructor.setSiteHome(site_home);
+	constructor.setProcessParams(option_list);
+	constructor.setActionType(process_mode);
+	constructor.addListener(processor);
+	constructor.start();
+    }
+    
+    static protected void printUsage() {
+	System.out.println("Usage: the following arguments need to be supplied:\n -site <site-home> -mode new|import|build|activate [options] <coll-name>");
+	System.out.println("Options available are:");
+	System.out.println("-maxdocs N\t process at most N documents\n"+
+			   "-gs2\t use greenstone 2 style building");
+    }
+
+    /** This event handler used to signify that a task has been started */
+    public void processBegun(ConstructionEvent evt) {
+	System.out.println("begun: "+evt.getMessage());
+    }
+    /** This event handler used to signify that a task has been completed */
+    public void processComplete(ConstructionEvent evt){
+	System.out.println("complete: "+evt.getMessage());
+    }
+    /** This event handler used to send status updates as the task is progressing */
+    public void processStatus(ConstructionEvent evt){
+	System.out.println(evt.getMessage());
+    }
+    /**  This event handler used to send any other messages to the listeners */
+    public void message(ConstructionEvent evt){
+	System.out.println(evt.getMessage());
+    }
+
+
+
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/build/ConstructionEvent.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/build/ConstructionEvent.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/build/ConstructionEvent.java	(revision 14125)
@@ -0,0 +1,42 @@
+package org.greenstone.gsdl3.build;
+
+import java.awt.AWTEvent;     
+
+public class ConstructionEvent 
+    extends AWTEvent {
+    
+    /** the event id for these events - use a random number thats
+	not reserved*/
+    private static final int EVENT_ID = RESERVED_ID_MAX+77;
+    /** The status associated with the event. */
+    private int status = -1;
+    /** Any message associated with this event. */
+    private String message = null;
+    /* Constructor.
+     * @param source The <strong>CollectionConstructor</strong> that fired this message.
+     * @param status The status code for this event          
+     * @param message A <strong>String</strong> representing any message attatched with this event.
+     */
+    public ConstructionEvent(Object source, int status, String message) {
+	super(source, EVENT_ID);
+	this.message = message;
+	this.status = status;
+    }
+    /** Gets the message associated with this event.
+     * @return The message as a <strong>String</strong> or <i>null</i>. 
+     */
+    public String getMessage() {
+	return this.message;
+    }
+    /** Gets the status associated with this event. This status can then be matched back to the constants in <strong>GShell</strong>.
+     * @return An <strong>int</strong> signifying the process status.
+     */
+    public int getStatus() {
+	return this.status;
+    }
+    /** returns a String representation of the event */
+    public String toString() {
+	return "org.greenstone.gsdl3.build.ConstructionEvent[" + this.message
++ "," + this.status + "]";
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/build/ConstructionListener.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/build/ConstructionListener.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/build/ConstructionListener.java	(revision 14125)
@@ -0,0 +1,16 @@
+package org.greenstone.gsdl3.build;
+
+import java.util.EventListener;
+
+public interface ConstructionListener 
+    extends EventListener {
+
+    /** This event handler used to signify that a task has been started */
+    public void processBegun(ConstructionEvent evt);
+    /** This event handler used to signify that a task has been completed */
+    public void processComplete(ConstructionEvent evt);
+    /** This event handler used to send status updates as the task is progressing */
+    public void processStatus(ConstructionEvent evt);
+    /**  This event handler used to send any other messages to the listeners */
+    public void message(ConstructionEvent evt);
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/build/GS2PerlConstructor.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/build/GS2PerlConstructor.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/build/GS2PerlConstructor.java	(revision 14125)
@@ -0,0 +1,297 @@
+package org.greenstone.gsdl3.build;
+
+// greenstome classes
+import org.greenstone.gsdl3.util.*;
+
+
+// xml classes
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+//general java classes
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.File;
+import java.util.Vector;
+
+/** CollectionConstructor class for greenstone 2 compatible building
+ * it uses the perl scripts to do the building stuff */
+public class GS2PerlConstructor 
+    extends CollectionConstructor {
+
+    public static final int NEW = 0;
+    public static final int IMPORT = 1;
+    public static final int BUILD = 2;
+    public static final int ACTIVATE = 3;
+
+    /** gsdlhome for greenstone 2 - we use the perl modules and building 
+     * scripts from there */
+    protected String gsdl2home = null; 
+    /** gsdlhome for gsdl3 - shouldn't need this eventually ??*/
+    protected String gsdl3home = null; 
+    /** gsdlos for greenstone 2 */
+    protected String gsdlos = null; 
+    /** the path environment variable */
+    protected String path = null;
+
+    public GS2PerlConstructor(String name) {
+	super(name);
+    }
+
+    /** retrieves the necessary environment variables */
+    public boolean configure() {
+	// try to get the environment variables
+	this.gsdl2home = System.getProperty("GSDLHOME");
+	this.gsdl3home = System.getProperty("GSDL3HOME");
+	this.gsdlos = System.getProperty("GSDLOS");
+	this.path = System.getProperty("PATH");
+	if (this.gsdl2home ==null ) {
+	    System.err.println("You must have greenstone2 installed, and GSDLHOME set for GS2Perl building to work!!");
+	    return false;
+	} 
+	if (this.gsdl3home == null|| this.gsdlos == null) {
+	   System.err.println("You must have GSDL3HOME and GSDLOS set for GS2Perl building to work!!");
+	    return false;
+	}  
+	if (this.path==null) {
+	    System.err.println("You must have the PATH set for GS2Perl building to work!!");
+	    return false;
+	}
+	return true;
+    }
+
+    public void run() {
+	String msg;
+	ConstructionEvent evt;
+	if (this.process_type == -1) {
+	    msg = "Error: you must set the action type";
+	    evt = new ConstructionEvent(this, GSStatus.ERROR, msg);
+	    sendMessage(evt);
+	    return;
+	}
+	if (this.site_home==null) { 
+	    msg = "Error: you must set site_home";
+	    evt = new ConstructionEvent(this, GSStatus.ERROR, msg);
+	    sendMessage(evt);
+	    return;
+	}
+	if (this.process_type != NEW && this.collection_name ==null) {
+	    msg = "Error: you must set collection_name";
+	    evt = new ConstructionEvent(this, GSStatus.ERROR, msg);
+	    sendMessage(evt);
+	    return;
+	}
+	
+	switch (this.process_type) {
+	case NEW:
+	    newCollection();
+	    break;
+	case IMPORT:
+	    importCollection();
+	    break;
+	case BUILD:
+	    buildCollection();
+	    break;
+	case ACTIVATE:
+	    activateCollection();
+	    break;
+	default:
+	    msg = "wrong type of action specified!";
+	    evt = new ConstructionEvent(this, GSStatus.ERROR, msg);
+	    sendMessage(evt);
+	    break;
+	}
+
+    }
+
+    protected void newCollection() {
+	sendMessage(new ConstructionEvent(this, GSStatus.INFO, "Collection construction: new collection."));
+	Vector command = new Vector();
+	command.add("gs2_mkcol.pl");
+	command.add("-site");
+	command.add(this.site_home);
+	command.add("-collectdir");
+	command.add(GSFile.collectDir(this.site_home));
+	command.addAll(extractParameters(this.process_params));
+	command.add(this.collection_name);
+	String [] command_str = {};
+	command_str = (String [])command.toArray(command_str); 
+	if (runPerlCommand(command_str)) {
+	    // success!! - need to send the final completed message
+	    sendProcessComplete(new ConstructionEvent(this, GSStatus.COMPLETED, ""));
+	} // else an error message has already been sent, do nothing
+	
+    }
+
+    protected void importCollection() {
+	sendMessage(new ConstructionEvent(this, GSStatus.INFO, "Collection construction: import collection."));
+	Vector command = new Vector();
+	command.add("import.pl");
+	command.add("-collectdir");
+	command.add(GSFile.collectDir(this.site_home));
+	command.addAll(extractParameters(this.process_params));
+	command.add(this.collection_name);
+	String [] command_str = {};
+	command_str = (String [])command.toArray(command_str); 
+
+	if (runPerlCommand(command_str)) {
+	    // success!! - need to send the final completed message
+	    sendProcessComplete(new ConstructionEvent(this, GSStatus.COMPLETED, ""));
+	} // else an error message has already been sent, do nothing
+    }
+
+     protected void buildCollection() {
+	sendMessage(new ConstructionEvent(this, GSStatus.INFO, "Collection construction: build collection."));
+	Vector command = new Vector();
+	command.add("buildcol.pl");
+	command.add("-collectdir");
+	command.add(GSFile.collectDir(this.site_home));
+	command.addAll(extractParameters(this.process_params));
+	command.add(this.collection_name);
+	String [] command_str = {};
+	command_str = (String [])command.toArray(command_str); 
+	
+	if (runPerlCommand(command_str)) {
+	    // success!! - need to send the final completed message
+	    sendProcessComplete(new ConstructionEvent(this, GSStatus.COMPLETED, ""));
+	}// else an error message has already been sent, do nothing
+//  	    
+
+     }
+    protected void activateCollection() {
+	sendMessage(new ConstructionEvent(this, GSStatus.INFO, "Collection construction: activate collection."));
+
+	// first check that we have a building directory
+	File build_dir = new File(GSFile.collectionBuildDir(this.site_home, this.collection_name));
+	if (!build_dir.exists()) {
+	    sendMessage(new ConstructionEvent(this, GSStatus.ERROR, "build dir doesn't exist!"));
+	    return;
+	}
+
+	// move building to index
+	File index_dir = new File(GSFile.collectionIndexDir(this.site_home, this.collection_name));
+	if (index_dir.exists()) {
+	    sendMessage(new ConstructionEvent(this, GSStatus.INFO, "deleting index directory"));
+	    index_dir.delete();
+	    if (index_dir.exists()) {
+		sendMessage(new ConstructionEvent(this, GSStatus.INFO, "index directory still exists!"));
+	    }
+	}
+
+	GSFile.moveDirectory(build_dir, index_dir);
+	if (!index_dir.exists()) {
+	    sendMessage(new ConstructionEvent(this, GSStatus.ERROR, "index dir wasn't created!"));
+	}
+
+	// run the convert coll script to convert the gs2 coll to gs3
+	Vector command = new Vector();
+	command.add("convert_coll_from_gs2.pl");
+	command.add("-collectdir");
+	command.add(GSFile.collectDir(this.site_home));
+	command.addAll(extractParameters(this.process_params));
+	command.add(this.collection_name);
+	String [] command_str = {};
+	command_str = (String [])command.toArray(command_str); 
+	
+	if (!runPerlCommand(command_str)) {
+	    // an error has occurred, dont carry on
+	    return;
+	}
+
+	// success!!  - need to send the final completed message
+	sendProcessComplete(new ConstructionEvent(this, GSStatus.COMPLETED, ""));
+    }
+
+    /** extracts all the args from the xml and returns them in a Vector */
+    protected Vector extractParameters(Element param_list) {
+
+	Vector args = new Vector();
+	if (param_list==null) {
+	    return args; // return an empty vector
+	}
+	NodeList params = param_list.getElementsByTagName(GSXML.PARAM_ELEM);
+	
+	for (int i=0; i<params.getLength(); i++) {
+	    Element p = (Element)params.item(i);
+	    String name = p.getAttribute(GSXML.NAME_ATT);
+	    String value=p.getAttribute(GSXML.VALUE_ATT);
+	    if (!name.equals("")) {
+		args.add("-"+name);
+		if (!value.equals("")) {
+		    args.add(value);
+		}
+	    }
+	}
+	    
+	return args;
+    }
+    /** returns true if completed correctly, false otherwise */
+    protected boolean runPerlCommand(String[] command) {
+	String msg;
+	ConstructionEvent evt;
+	
+	String args[] = {"GSDLHOME="+this.gsdl2home, "GSDL3HOME="+this.gsdl3home, "GSDLOS="+this.gsdlos, "PATH="+this.path};
+	String command_str = "";
+	for(int i = 0; i < command.length; i++) {
+	    command_str = command_str + command[i] + " ";
+	}
+	sendMessage(new ConstructionEvent(this, GSStatus.INFO, "command = "+command_str));
+	try {
+	    Runtime rt = Runtime.getRuntime();
+	    sendProcessBegun(new ConstructionEvent(this, GSStatus.ACCEPTED, "starting"));
+	    Process prcs = rt.exec(command, args);
+
+	    InputStreamReader eisr = new InputStreamReader( prcs.getErrorStream() );
+	    InputStreamReader stdinisr = new InputStreamReader( prcs.getInputStream() );
+	    BufferedReader ebr = new BufferedReader( eisr );
+	    BufferedReader stdinbr = new BufferedReader( stdinisr );
+	    // Captures the std err of a program and pipes it into
+	    // std in of java
+	    String eline = null;
+	    String stdinline = null;
+	    while (((eline = ebr.readLine()) != null || (stdinline = stdinbr.readLine()) != null) && !this.cancel) {
+		if(eline != null) {
+		    sendProcessStatus(new ConstructionEvent(this, GSStatus.CONTINUING, eline));
+		}
+		if(stdinline != null) {
+		    sendProcessStatus(new ConstructionEvent(this, GSStatus.CONTINUING, stdinline));
+		}
+	    }
+	    if(!this.cancel) {
+		// Now display final message based on exit value
+		prcs.waitFor();
+		
+		if(prcs.exitValue() == 0) {
+		    //status = OK;
+		    sendProcessStatus(new ConstructionEvent(this, GSStatus.CONTINUING, "Success"));
+		    
+		} else {
+		    //status = ERROR;
+		    sendProcessStatus(new ConstructionEvent(this, GSStatus.ERROR, "Failure"));
+		   
+		    return false;
+		    
+		}
+	    }
+	    else {
+		// I need to somehow kill the child process. Unfortunately Thread.stop() and Process.destroy() both fail to do this. But now, thankx to the magic of Michaels 'close the stream suggestion', it works fine.
+		sendProcessStatus(new ConstructionEvent(this, GSStatus.HALTED, "killing the process"));
+		prcs.getOutputStream().close();
+		prcs.destroy();
+		//status = ERROR;
+		return false;
+	    }
+	    
+	} catch (Exception e) {
+	    sendProcessStatus(new ConstructionEvent(this, GSStatus.ERROR, "Exception occurred "+e.toString()));
+	}
+
+	// we're done, but we dont send a process complete message here cos there ight be stuff to do after this has finished.
+	return true;
+
+    }
+   
+
+
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/build/GS2PerlListener.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/build/GS2PerlListener.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/build/GS2PerlListener.java	(revision 14125)
@@ -0,0 +1,62 @@
+package org.greenstone.gsdl3.build;
+
+public class GS2PerlListener 
+    implements ConstructionListener {
+
+    /** a buffer holding all the messages */
+    protected StringBuffer log=null;
+    /** a buffer holding only the latest update */
+    protected StringBuffer update = null;
+
+    /** a status code */
+    protected int status = -1;
+    /** whether the process this is listeneing to is finshed */
+    protected boolean finished = false;
+
+    public GS2PerlListener() {
+	this.log = new StringBuffer();
+	this.update = new StringBuffer();
+    }
+
+    public boolean isFinished() {
+	return this.finished;
+    }
+    public String getLog() {
+	return this.log.toString();
+    }
+    public int getStatus() {
+	return this.status;
+    }
+    synchronized public String getUpdate() {
+	this.log.append(this.update);
+	String tmp = this.update.toString();
+	this.update.delete(0, this.update.length());
+	return tmp;
+    }
+
+    // do we need to synchronize the methods below?
+
+    /** This event handler used to signify that a task has been started */
+    synchronized public void processBegun(ConstructionEvent evt) {
+	this.status = evt.getStatus();
+	this.update.append(evt.getMessage()+"\n");
+	
+    }
+    /** This event handler used to signify that a task has been completed */
+    synchronized public void processComplete(ConstructionEvent evt){
+	this.status = evt.getStatus();
+	this.update.append(evt.getMessage()+"\n");
+    }
+    /** This event handler used to send status updates as the task is progressing */
+    synchronized public void processStatus(ConstructionEvent evt){
+	this.status = evt.getStatus();
+	this.update.append(evt.getMessage()+"\n");
+    }
+    /**  This event handler used to send any other messages to the listeners */
+    synchronized public void message(ConstructionEvent evt){
+	this.status = evt.getStatus();
+	this.update.append(evt.getMessage()+"\n");
+    }
+
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/build/StatusDisplay.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/build/StatusDisplay.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/build/StatusDisplay.java	(revision 14125)
@@ -0,0 +1,188 @@
+package org.greenstone.gsdl3.build;
+
+import java.applet.Applet;
+import java.awt.*;
+import java.awt.event.*;
+
+import org.greenstone.gsdl3.util.*;
+import org.w3c.dom.Element;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.apache.xerces.parsers.DOMParser;
+import java.net.URL;
+import java.io.DataInputStream;
+
+
+/** StatusDisplay - a java applet thats sends a message at regular intervals 
+ * to a pre specified address (the library param) and then displays the 
+ * status messages received.
+ * to use, embed in a web page using something like: (note the cgi args may differ - see process.xsl for details )
+ * <applet code="org.greenstone.gsdl3.build.StatusDisplay.class" codebase='lib/java' archive='gsdl3.jar, xercesImpl.jar, jaxp.jar, xml-apis.jar' width='537' height='100'>The status display applet.<param name='library' value='mylibrary?a=pr&rt=s&c=build&o=xml&ro=1&s=ImportCollection&l=en&coll=demo'/></applet>
+ * the cgi params for the library param are dependent on what action/service 
+ *  is using the applet
+ */
+public class StatusDisplay extends Applet 
+    implements Runnable {
+
+    /** the display area for the status messages */
+    protected TextArea display;
+    /** how long to delay between requests */
+    protected int delay=3000; // 3 secs
+    /** the thread used */
+    protected Thread updator_thread;
+    /** the url for the requests */ 
+    protected URL status_cgi = null;
+    /** if true, stops sending requests, and cant be unset */
+    protected boolean completed = false;
+    // init is called if you leave the page and go back - need to somehow retrieve all the previous messages that have been obtained cos we may have left the page and gone back to it during an import or something. dont want to lose all the info.
+    public void init() {
+	//Create the text field and make it uneditable.
+	this.display = new TextArea();
+	this.display.setEditable(false);
+	this.display.setBackground(Color.white);
+	//Set the layout manager so that the text field will be
+	//as wide as possible.
+	setLayout(new java.awt.GridLayout(1,0));
+
+	//Add the text field to the applet.
+	add(this.display);
+	validate();
+
+	// add the initial status text
+	String initial_text = parameterValue("initial_text");
+	addItem(initial_text);
+
+	// check the initial error state - there may be no more messages to come
+	this.completed = GSStatus.isCompleted(Integer.parseInt(parameterValue("initial_code")));
+		
+	// we always do the same query
+	String library = parameterValue("library");
+	library = tidy_URL(library);
+	try {
+	    this.status_cgi = new URL(library);
+	} catch (Exception e) {
+	    System.out.println("Error creating URL for "+library+": "+e.getMessage());
+	}
+    }
+    
+    public void start() {
+	if (this.completed) {
+	    // do nothing
+	} else {
+	    if (this.updator_thread == null) {
+		this.updator_thread = new Thread(this);
+	    }
+	    this.updator_thread.start();
+	}
+    }
+    public void stop() {
+	this.updator_thread = null;
+    }
+    public void run() {
+	
+	if (this.completed) { // do nothing. dont know if we need this here
+	    return;
+	}
+        //Just to be nice, lower this thread's priority
+        //so it can't interfere with other processing going on.
+        Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
+
+        //Remember which thread we are.
+        Thread current_thread = Thread.currentThread();
+
+        //This is the  loop.
+        while (current_thread == this.updator_thread && !this.completed) {
+	    queryServer();
+            this.display.repaint();
+	    
+            //Delay for the specified time
+            try {
+		Thread.sleep(this.delay);
+            } catch (InterruptedException e) {
+                break;
+            }
+        }
+    }
+
+    /** add some more text to the display    */
+    void addItem(String new_text) {
+	String t = this.display.getText()+"\n"+new_text;
+	this.display.setText(t);
+	this.display.setCaretPosition(t.length()); // so that you always see the 
+	// most recent entries - ie so that it scrolls down automatically
+	repaint();
+    }
+    
+    void queryServer() {
+
+	// Send the query 
+	System.out.println("sending query: " + this.status_cgi); // this appears in the java console
+	try {
+	    DataInputStream in = new DataInputStream(this.status_cgi.openStream());
+	    DOMParser parser = new DOMParser();
+	    parser.parse(new InputSource(in));
+	    Document data_doc = parser.getDocument();
+	    Element data_elem = data_doc.getDocumentElement();
+	    Element status_elem = (Element)GSXML.getChildByTagName(data_elem, GSXML.STATUS_ELEM);
+	    if (status_elem != null) {
+		String status = status_elem.getAttribute(GSXML.STATUS_ERROR_CODE_ATT);
+		System.out.println("received status "+status);
+		this.completed = GSStatus.isCompleted(Integer.parseInt(status));
+		addItem(GSXML.getNodeText(status_elem));
+	    } else {
+		System.out.println("Error - no status receieved");
+		this.completed=true;
+	    }
+	    in.close();
+	} catch (Exception e) {
+	    System.err.println( "Error sending query ("+this.status_cgi+"): " + e);
+	}
+
+    }
+  
+    // Get a REQUIRED string.  Stop the applet if we cannot.
+    String parameterValue(String name) {
+	try { 
+	    return getParameter(name);
+	} catch (Exception e) {
+	    System.err.println("StatusDisplay: you must give a parameter for \""+ name + "\".  Stopping.");
+	    stop();
+	}
+	return "";
+    }
+
+    /**Tidy up URLs
+     *
+     * Ensure a URL address (as string) has a protocol, host, and file.
+     */
+    String tidy_URL(String address) {
+
+	// make sure the URL has protocol, host, and file
+	if (address.startsWith("http")) {
+	    // the address has all the necessary components
+	} else if (address.startsWith("/")) {
+	    // there is not protocol and host
+	    URL document = getDocumentBase();
+	    String port = "";
+	    if (document.getPort()!=-1) {
+		port = ":" + document.getPort();
+	    }
+	    address = "http://" + document.getHost() + port  + address;
+	} else {
+	    // this URL is relative to the directory the document is in
+	    URL document = getDocumentBase();
+	    String directory = document.getFile();
+	    int end = directory.lastIndexOf('/');
+	    String port = "";
+	    if (document.getPort()!=-1) {
+		port = ":" + document.getPort();
+	    }
+	    directory = directory.substring(0,end + 1);
+	    address = "http://" + document.getHost() + port + directory + address;
+
+	}
+
+	return address;
+    }
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/collection/Collection.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/collection/Collection.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/collection/Collection.java	(revision 14125)
@@ -0,0 +1,254 @@
+/*
+ *    Collection.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.collection;
+
+import org.greenstone.gsdl3.util.*;
+import org.greenstone.gsdl3.core.*;
+import org.greenstone.gsdl3.service.*;
+
+
+// java XML classes we're using
+import org.w3c.dom.Document; 
+import org.w3c.dom.Node; 
+import org.w3c.dom.Element; 
+import org.w3c.dom.NodeList; 
+
+import java.io.File;
+import java.util.HashMap;
+
+import org.apache.log4j.*;
+
+/**
+ * Represents a collection in Greenstone. A collection is an extension of
+ * a ServiceCluster - it has local data that the services use.
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @version $Revision$
+ * @see ModuleInterface
+ */
+public class Collection 
+    extends ServiceCluster {
+
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.collection.Collection.class.getName());
+
+    /** is this collection being tidied */
+    protected boolean useBook = false;
+    /** is this collection public or private */
+    protected boolean is_public = true;
+    protected XMLTransformer transformer = null;
+    /** same as setClusterName */
+    public void setCollectionName(String name) {
+	setClusterName(name);
+    }
+
+    public Collection() {
+	super();
+	this.description = this.doc.createElement(GSXML.COLLECTION_ELEM);
+	
+    }
+	
+    /**
+     * Configures the collection.
+     *
+     * gsdlHome and collectionName must be set before configure is called.
+     *
+     * the file buildcfg.xml is located in gsdlHome/collect/collectionName
+     * collection metadata is obtained, and services loaded.
+     *
+     * @return true/false on success/fail
+     */
+    public boolean configure() {
+	
+	if (this.site_home == null || this.cluster_name== null) {
+	    logger.error("Collection: site_home and collection_name must be set before configure called!");
+	    return false;
+	}
+	
+	Element coll_config_xml = loadCollConfigFile();
+	Element build_config_xml = loadBuildConfigFile();
+	
+	if (coll_config_xml==null||build_config_xml==null) {
+	    return false;
+	}
+	// process the metadata and display items
+	findAndLoadInfo(coll_config_xml, build_config_xml);
+	
+	// now do the services	
+	Element service_list = (Element)GSXML.getChildByTagName(build_config_xml, GSXML.SERVICE_CLASS_ELEM+GSXML.LIST_MODIFIER);
+	configureServiceRack(service_list, coll_config_xml);
+	
+	return true;
+	
+    }
+
+    public boolean useBook() {
+    	return useBook;
+    }
+    
+    public boolean isPublic() {
+	return is_public;
+    }
+    /** 
+     * load in the collection config file into a DOM Element 
+     */    
+    protected Element loadCollConfigFile() {
+
+	File coll_config_file = new File(GSFile.collectionConfigFile(this.site_home, this.cluster_name));
+	
+	if (!coll_config_file.exists()) {
+	    logger.error("Collection: couldn't configure collection: "+this.cluster_name+", "+coll_config_file+" does not exist");
+	    return null;
+	}
+	// get the xml for both files
+	Document coll_config_doc = this.converter.getDOM(coll_config_file, CONFIG_ENCODING);
+	Element coll_config_elem = null;
+	if (coll_config_doc != null) {
+	    coll_config_elem = coll_config_doc.getDocumentElement();
+	}
+	return coll_config_elem;
+
+    }
+    
+    /** 
+     * load in the collection build config file into a DOM Element 
+     */        
+    protected Element loadBuildConfigFile() {
+	
+	File build_config_file = new File(GSFile.collectionBuildConfigFile(this.site_home, this.cluster_name));
+	if (!build_config_file.exists()) {
+	    logger.error("Collection: couldn't configure collection: "+this.cluster_name+", "+build_config_file+" does not exist");
+	    return null;
+	}
+	Document build_config_doc = this.converter.getDOM(build_config_file, CONFIG_ENCODING);
+	Element build_config_elem = null;
+	if (build_config_doc != null) {
+	    build_config_elem = build_config_doc.getDocumentElement();
+	}
+	return build_config_elem;
+    }
+
+    /**
+     * find the metadata and display elems from the two config files and add it to the appropriate lists
+     */
+    protected boolean findAndLoadInfo(Element coll_config_xml, 
+				      Element build_config_xml){
+
+	// metadata
+	Element meta_list = (Element)GSXML.getChildByTagName(coll_config_xml, GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+	addMetadata(meta_list);
+	meta_list = (Element)GSXML.getChildByTagName(build_config_xml, GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+	addMetadata(meta_list);
+
+	meta_list = this.doc.createElement(GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER);
+	GSXML.addMetadata(this.doc, meta_list, "httpPath", this.site_http_address+"/collect/"+this.cluster_name);
+	addMetadata(meta_list);
+
+	// display stuff
+	Element display_list = (Element)GSXML.getChildByTagName(coll_config_xml, GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER);
+	if (display_list != null) {
+	    resolveMacros(display_list);
+	    addDisplayItems(display_list);
+	}
+
+	//check whether the html are tidy or not
+	Element import_list = (Element)GSXML.getChildByTagName(coll_config_xml, GSXML.IMPORT_ELEM);
+	if (import_list != null) {
+		Element plugin_list = (Element)GSXML.getChildByTagName(import_list, GSXML.PLUGIN_ELEM+GSXML.LIST_MODIFIER);
+		addPlugins(plugin_list);
+		if (plugin_list != null){
+			Element plugin_elem = (Element)GSXML.getNamedElement(plugin_list, GSXML.PLUGIN_ELEM, GSXML.NAME_ATT, "HTMLPlug");
+			if (plugin_elem != null) {
+				//get the option
+				Element option_elem = (Element)GSXML.getNamedElement(plugin_elem, GSXML.PARAM_OPTION_ELEM, GSXML.NAME_ATT, "-tidy_html");
+				if (option_elem != null) {
+					useBook = true;
+				}
+			}
+		}	
+	}
+	meta_list = this.doc.createElement(GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER);
+	if (useBook == true)
+		GSXML.addMetadata(this.doc, meta_list, "tidyoption", "tidy");
+	else
+		GSXML.addMetadata(this.doc, meta_list, "tidyoption", "untidy");
+	addMetadata(meta_list);
+	
+	// check whether we are public or not
+	if (meta_list != null) {
+	    Element meta_elem = (Element) GSXML.getNamedElement(metadata_list, GSXML.METADATA_ELEM, GSXML.NAME_ATT, "public");
+	    if (meta_elem != null) {
+		String value = GSXML.getValue(meta_elem).toLowerCase().trim();
+		if (value.equals("false")) {
+		    is_public = false;
+		}
+	    }
+	}
+	return true;
+
+    }
+
+    protected boolean resolveMacros(Element display_list) {
+	if (display_list==null) return false;
+	NodeList displaynodes = display_list.getElementsByTagName(GSXML.DISPLAY_TEXT_ELEM);
+	if (displaynodes.getLength()>0) { 
+	    String http_site = this.site_http_address;
+	    String http_collection = this.site_http_address +"/collect/"+this.cluster_name;
+	    for(int k=0; k<displaynodes.getLength(); k++) {
+		Element d = (Element) displaynodes.item(k);
+		String text = GSXML.getNodeText(d);
+		text = text.replaceAll("_httpsite_", http_site);
+		text = text.replaceAll("_httpcollection_", http_collection);
+		GSXML.setNodeText(d, text);
+	    }
+	}
+	return true;
+    }
+    /** 
+     * do a configure on only part of the collection
+     */
+    protected boolean configureSubset(String subset) {
+
+	// need the coll config files
+	Element coll_config_elem = loadCollConfigFile();
+	Element build_config_elem = loadBuildConfigFile();
+	if (coll_config_elem == null||build_config_elem == null) {
+	    // wont be able to do any of teh requests
+	    return false;
+	}    
+	
+	if (subset.equals(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER)) {
+	    Element service_rack_list = (Element)GSXML.getChildByTagName(build_config_elem, GSXML.SERVICE_CLASS_ELEM+GSXML.LIST_MODIFIER);
+	    
+	    return configureServiceRack(service_rack_list, coll_config_elem);
+	} 
+
+	if (subset.equals(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER) || subset.equals(GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER) || subset.equals(GSXML.PLUGIN_ELEM+GSXML.LIST_MODIFIER)) {
+	    return findAndLoadInfo(coll_config_elem, build_config_elem);
+	    
+	}
+	
+	logger.error("Collection: cant process system request, configure "+subset);
+	return false;
+    } 
+
+}
+
+
+
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/collection/ServiceCluster.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/collection/ServiceCluster.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/collection/ServiceCluster.java	(revision 14125)
@@ -0,0 +1,674 @@
+/*
+ *    ServiceCluster.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+// leave the package name as is for now - should be changed to something better
+// cluster? groups?
+package org.greenstone.gsdl3.collection;
+
+
+import org.greenstone.gsdl3.util.*;
+import org.greenstone.gsdl3.core.*;
+import org.greenstone.gsdl3.service.*;
+
+// java XML classes we're using
+import org.w3c.dom.Document; 
+import org.w3c.dom.Node; 
+import org.w3c.dom.Element; 
+import org.w3c.dom.NodeList; 
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.apache.log4j.*;
+
+/* ServiceCluster - a groups of services that are related in some way
+ * Implements ModuleInterface. Contains a list of services provided by the cluster, along with metadata about the cluster itself.
+ * a collection is a special type of cluster
+ *  @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ *  @version $Revision$
+ *  @see ModuleInterface
+ */
+public class ServiceCluster  
+    implements ModuleInterface {
+
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.collection.ServiceCluster.class.getName()); 
+
+    protected static final String CONFIG_ENCODING = "utf-8";
+
+    protected static final String DEFAULT_LANG = "en"; // hack for now, should be read from the coll cfg file? or site cfg file for cluster
+    
+    /** base directory for the site that this cluster belongs to*/
+    protected String site_home = null;
+    /** http address of the site that this cluster belongs to */
+    protected String site_http_address = null;
+    /** The name of the cluster - for a collection, this is the collection name*/
+    protected String cluster_name = null;
+
+    /** a reference to the message router */
+    protected MessageRouter router = null;
+    /** The map of services.
+     *
+     * Maps Services to ServiceRack objects
+     * @see ServiceRack
+     *
+     */
+    protected HashMap service_map=null;
+    /** maps pseudo service names to real service names - needed if we have two services with the same name for one collection */
+    protected HashMap service_name_map=null;
+    
+    /** XML converter for String to DOM and vice versa */
+    protected XMLConverter converter=null;
+
+    /** container doc for description elements */
+    protected Document doc = null;
+    /** list of services */
+    protected Element service_list = null;
+    /** list of metadata - all metadata, regardless of language goes in here */
+    protected Element metadata_list = null;
+    /** language specific stuff */
+    //protected Element lang_specific_metadata_list = null;
+    protected Element display_item_list = null;
+    /** the element that will have any descriptions passed back in */
+    protected Element description = null;
+
+    /** list of plugin */
+    protected Element plugin_item_list = null;
+    
+    public void setSiteHome(String home) {
+	this.site_home = home;
+    }
+
+    public void setSiteAddress(String address) {
+	this.site_http_address = address;
+    }
+
+    public void cleanUp() {
+	Iterator i = this.service_map.values().iterator();
+	while (i.hasNext()) {
+	    ServiceRack s = (ServiceRack)i.next();
+	    s.cleanUp();
+	}
+    }
+    public void setClusterName(String name) {
+	this.cluster_name = name;	
+	this.description.setAttribute(GSXML.NAME_ATT, name);
+    }  
+
+    public void setMessageRouter(MessageRouter m) {
+	this.router = m;
+    }
+
+    public ServiceCluster() {
+	this.service_map = new HashMap();
+	this.service_name_map = new HashMap();
+	this.converter = new XMLConverter();
+	this.doc = this.converter.newDOM();
+	this.description = this.doc.createElement(GSXML.CLUSTER_ELEM);
+	this.display_item_list = this.doc.createElement(GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER);
+	this.metadata_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+	this.plugin_item_list = this.doc.createElement(GSXML.PLUGIN_ELEM+GSXML.LIST_MODIFIER);
+    }
+
+    /**
+     * Configures the cluster.
+     *
+     * gsdlHome and clusterName must be set before configure is called.
+     *
+     * reads the site configuration file, and configures itself
+     * this calls configure(Element) with the XML element node from the config
+     * file.
+     * configure(Element) should be used if the config file has already been 
+     * parsed.  This method will work with any subclass.
+     * 
+     * @return true if configure successful, false otherwise.
+     */
+    public boolean configure() {
+
+	if (this.site_home == null || this.cluster_name== null) {
+	    logger.error("site_home and cluster_name must be set before configure called!");
+	    return false;
+	}
+	logger.info("configuring service cluster");
+	// read the site configuration file
+	File config_file = new File(GSFile.siteConfigFile(this.site_home));
+
+	if (!config_file.exists()) {
+	    logger.error("couldn't configure cluster: "+this.cluster_name +", "+config_file+" does not exist");
+	    return false;
+	}
+
+	Document doc = this.converter.getDOM(config_file, CONFIG_ENCODING);
+	if (doc == null) {
+	    logger.error("couldn't parse config file "+config_file.getPath());
+	    return false;
+	}
+	
+	// get the appropriate service cluster element
+	Element cluster_list = (Element)GSXML.getChildByTagName(doc.getDocumentElement(), GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER);
+	Element sc = GSXML.getNamedElement(cluster_list, GSXML.CLUSTER_ELEM,
+					   GSXML.NAME_ATT, this.cluster_name);
+	
+	return this.configure(sc);
+    }
+    
+    
+    public boolean configure(Element service_cluster_info) {
+	
+	// get the metadata - for now just add it to the list
+	Element meta_list = (Element) GSXML.getChildByTagName(service_cluster_info, GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+	if (meta_list !=null) {
+	    if (!addMetadata(meta_list)) {
+		
+		logger.error(" couldn't configure the metadata");
+	    }
+	}
+	
+	// get the display info
+	Element display_list = (Element) GSXML.getChildByTagName(service_cluster_info, GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER);
+	if (display_list !=null) {
+	    if (!addDisplayItems(display_list)) {
+		
+		logger.error("couldn't configure the display items");
+	    }
+	}
+	
+	//get the plugin info
+	Element import_list = (Element) GSXML.getChildByTagName(service_cluster_info, GSXML.IMPORT_ELEM);
+	if (import_list != null)
+	{
+		Element plugin_list = (Element) GSXML.getChildByTagName(service_cluster_info, GSXML.PLUGIN_ELEM+GSXML.LIST_MODIFIER);
+		if (plugin_list !=null) {
+	   	 	if (!addPlugins(plugin_list)) {
+		
+				logger.error("couldn't configure the plugins");
+	    		}
+		}
+	}	
+	
+	// do the service racks
+	Element service_rack_list = (Element)GSXML.getChildByTagName(service_cluster_info, GSXML.SERVICE_CLASS_ELEM+GSXML.LIST_MODIFIER);
+	if (service_rack_list == null) {
+	    // is this an error? could you ever have a service cluster
+	    // without service racks???
+	    logger.error("cluster has no service racks!!");
+	} else {
+	    
+	    if (!configureServiceRack(service_rack_list, null)) {
+		logger.error("couldn't configure the  service racks!!");
+		return false;
+	    }
+	}
+
+	return true;
+    }
+    
+    /** adds metadata from a metadataList into the metadata_list xml 
+     */
+    protected boolean addMetadata(Element metadata_list) {
+	if (metadata_list == null) return false;
+	NodeList metanodes = metadata_list.getElementsByTagName(GSXML.METADATA_ELEM);
+	if (metanodes.getLength()>0) { 	
+	    for(int k=0; k<metanodes.getLength(); k++) {
+		this.metadata_list.appendChild(this.doc.importNode(metanodes.item(k), true));
+	    }
+	}
+	
+	return true;
+    }
+
+    protected boolean addDisplayItems(Element display_list) {
+	
+	if (display_list==null) return false;
+	NodeList displaynodes = display_list.getElementsByTagName(GSXML.DISPLAY_TEXT_ELEM);
+	if (displaynodes.getLength()>0) { 	
+	    for(int k=0; k<displaynodes.getLength(); k++) {
+		Element d = (Element) displaynodes.item(k);
+		String lang = d.getAttribute(GSXML.LANG_ATT);
+		if (lang==null||lang.equals("")) {
+		    //set the lang to teh default
+		    d.setAttribute(GSXML.LANG_ATT, DEFAULT_LANG);
+		}
+		String name = d.getAttribute(GSXML.NAME_ATT);
+		Element this_item = GSXML.getNamedElement(this.display_item_list, GSXML.DISPLAY_TEXT_ELEM, GSXML.NAME_ATT, name);
+		if (this_item==null) {
+		    this_item = this.doc.createElement(GSXML.DISPLAY_TEXT_ELEM);
+		    this_item.setAttribute(GSXML.NAME_ATT, name);
+		    this.display_item_list.appendChild(this_item);
+		}
+		
+		this_item.appendChild(this.doc.importNode(d, true));
+	    }
+	}
+	
+	return true;
+    }
+    
+    protected boolean addPlugins(Element plugin_list) {
+    	if (plugin_list == null) return false;
+	NodeList pluginNodes = plugin_list.getElementsByTagName(GSXML.PLUGIN_ELEM);
+	if (pluginNodes.getLength() > 0) {
+		for (int k = 0; k < pluginNodes.getLength(); k++)
+		{
+			this.plugin_item_list.appendChild(this.doc.importNode(pluginNodes.item(k), true));
+		}
+	}
+	
+	return true;
+    }
+    
+    /** creates and configures all the services - extra_info is some more xml 
+that is passed to teh service  - eg used for coll config files for Collection
+    */
+    protected boolean configureServiceRack(Element service_rack_list, 
+					   Element extra_info) {
+
+	// empty the service map in case this is a reconfigure
+	service_map.clear();
+	this.service_list = this.doc.createElement(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER);
+
+	// create all the services
+	NodeList nodes = service_rack_list.getElementsByTagName(GSXML.SERVICE_CLASS_ELEM);
+	if (nodes.getLength()==0) {
+	    logger.error("ServiceCluster configuration error: cluster "+this.cluster_name+" has no service modules!");
+	    return false;
+	}
+
+	for(int i=0; i<nodes.getLength(); i++) {
+	
+	    // the xml request to send to the serviceRack to query what
+	    // services it provides
+	    Element message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	    Element request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, "", "", "");
+	    message.appendChild(request);
+
+	    Element n = (Element)nodes.item(i);
+	    String servicetype = n.getAttribute(GSXML.NAME_ATT);
+	    
+	    ServiceRack s = null;
+	    
+	    try {
+		// try for a default service in standard package
+		s = (ServiceRack)Class.forName("org.greenstone.gsdl3.service."+servicetype).newInstance();
+		
+	    } catch (Exception e) {}
+	    if (s == null) {
+		try {
+		    // name as is, in case package is already specified
+		    s = (ServiceRack)Class.forName(servicetype).newInstance();
+		} catch (Exception e) {}
+	    }
+
+	    if (s == null) {
+		logger.error("Couldn't get an instance of class "+servicetype+", or org.greenstone.gsdl3.service."+servicetype);
+		continue;
+	    }
+
+	    
+	    s.setSiteHome(this.site_home);
+	    s.setSiteAddress(this.site_http_address);
+	    s.setClusterName(this.cluster_name);
+	    s.setMessageRouter(this.router);
+	    // pass the xml node to the service for configuration
+	    if (s.configure(n, extra_info)) {
+		
+		// find out the supported service types for this service module
+		Node types = s.process(message);
+		NodeList typenodes = ((Element)types).getElementsByTagName(GSXML.SERVICE_ELEM);	   
+		
+		for (int j=0; j<typenodes.getLength();j++) {
+		    String service = ((Element) typenodes.item(j)).getAttribute(GSXML.NAME_ATT);	   
+		    if (service_map.get(service)!=null) {
+			char extra = '0';
+			String new_service = service+extra;	   
+			
+			while (service_map.get(new_service)!=null) {
+			    extra++;
+			    new_service = service+extra;
+			}
+			this.service_name_map.put(new_service, service);
+			service=new_service;
+			((Element) typenodes.item(j)).setAttribute(GSXML.NAME_ATT, service);
+		    }
+		    this.service_map.put(service, s);
+		    // also add info to the ServiceInfo XML element
+		    this.service_list.appendChild(this.doc.importNode(typenodes.item(j), true));
+		}
+	    }
+	} 
+	
+	return true;
+	
+	
+    }
+
+
+    /**
+     * Process an XML document - uses Strings 
+     *  just calls process(Node).
+     *
+     * @param in the Document to process - a string
+     * @return the resultant document as a string - contains any error messages
+     * @see String
+     */
+    public String process(String in) {
+
+	Document doc = this.converter.getDOM(in);
+	Element e = doc.getDocumentElement();
+	
+	Element res = process(e);
+	return this.converter.getString(res);
+	
+    }
+    
+    /** process XML as Node
+     *
+     */
+    public Element process(Element message) {
+
+	NodeList requests = message.getElementsByTagName(GSXML.REQUEST_ELEM);
+	Document mess_doc = message.getOwnerDocument();
+	Element mainResult = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	if (requests.getLength()==0) {
+	    logger.error("no requests for cluster:"+this.cluster_name);
+	    // no requests
+	    return mainResult; // for now
+	}
+	for (int i=0; i<requests.getLength(); i++) {
+	    Element request = (Element)requests.item(i);
+	    String to = request.getAttribute(GSXML.TO_ATT);
+
+	    // the cluster name should be first, check, then remove
+	    String clustername = GSPath.getFirstLink(to);
+	    if (!clustername.equals(this.cluster_name)){ 
+		logger.error("cluster name wrong! was "+clustername+" should have been "+this.cluster_name);
+		continue; // ignore this request
+	    }
+	    to = GSPath.removeFirstLink(to);
+	    request.setAttribute(GSXML.TO_ATT, to);
+	   
+	    if (to.equals("")) { // this command is for me
+		Element response = processMessage(request);
+		mainResult.appendChild(response);
+		
+	    } else { // the request is for one of my services
+		String service = GSPath.getFirstLink(to);
+		
+		if (!this.service_map.containsKey(service)) {
+		    logger.error("non-existant service, "+service+", specified!");
+		    continue;
+		}
+		String real_service = service;
+		if (this.service_name_map.containsKey(service)) {
+		    real_service = (String)this.service_name_map.get(service);
+		    // need to change the to att in the request - give the real service name
+		    to = request.getAttribute(GSXML.TO_ATT);
+		    String old_to = to;
+		    to = GSPath.replaceFirstLink(to, real_service);
+		    request.setAttribute(GSXML.TO_ATT, to);
+		}
+		// have to pass the request to the service
+		Element single_message = mess_doc.createElement(GSXML.MESSAGE_ELEM);
+		single_message.appendChild(request);
+		Element response_message = ((ModuleInterface)this.service_map.get(service)).process(single_message);
+		if (response_message != null) {
+		    Element response = (Element) GSXML.getChildByTagName(response_message, GSXML.RESPONSE_ELEM);
+		    String from = response.getAttribute(GSXML.FROM_ATT);
+		    if (!real_service.equals(service)) {
+			// replace the real service name with the pseudo service name
+			from = GSPath.replaceFirstLink(from, service);
+			// also need to do it in the service itself
+			// shoudl this be done here??
+			Element service_elem = (Element) GSXML.getChildByTagName(response, GSXML.SERVICE_ELEM);
+			if (service_elem!= null) {
+			    service_elem.setAttribute(GSXML.NAME_ATT, service);
+			}
+		    }
+		    from = GSPath.prependLink(from, this.cluster_name);
+		    response.setAttribute(GSXML.FROM_ATT, from);
+		    mainResult.appendChild(this.doc.importNode(response, true));
+		}
+		  
+	    } // else
+		
+	   
+	} // for each request
+	return mainResult;
+    }
+
+    /** handles requests made to the ServiceCluster itself 
+     *
+     * @param req - the request Element- <request>
+     * @return the result Element - should be <response>
+     */
+    protected Element processMessage(Element request) {
+
+	Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	response.setAttribute(GSXML.FROM_ATT, this.cluster_name);
+	String type = request.getAttribute(GSXML.TYPE_ATT);
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	response.setAttribute(GSXML.TYPE_ATT, type);
+	
+	if (type.equals(GSXML.REQUEST_TYPE_DESCRIBE)) {
+	    // create the collection element
+	    Element description = (Element)this.description.cloneNode(false);
+	    response.appendChild(description);
+	    // check the param list
+	    Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	    if (param_list == null) {
+		addAllDisplayInfo(description, lang);
+		description.appendChild(this.service_list);
+		description.appendChild(this.metadata_list);
+		description.appendChild(this.plugin_item_list);
+		return response;
+	    }
+	    
+	    // go through the param list and see what components are wanted
+	    NodeList params = param_list.getElementsByTagName(GSXML.PARAM_ELEM);
+	    for (int i=0; i<params.getLength(); i++) {
+		
+		Element param = (Element)params.item(i);
+		// Identify the structure information desired
+		if (param.getAttribute(GSXML.NAME_ATT).equals(GSXML.SUBSET_PARAM)) {
+		    String info = param.getAttribute(GSXML.VALUE_ATT);
+		    if (info.equals(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER)) {
+			description.appendChild(this.service_list);
+		    } else if (info.equals(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER)) {
+			description.appendChild(metadata_list);
+		    } else if (info.equals(GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER)) {
+			addAllDisplayInfo(description, lang);
+		    } else if (info.equals(GSXML.PLUGIN_ELEM+GSXML.LIST_MODIFIER)) {
+		    	description.appendChild(plugin_item_list);
+		    }
+		}
+	    }
+	    return response;
+	}
+	
+	if (type.equals(GSXML.REQUEST_TYPE_SYSTEM)) {
+	    response = processSystemRequest(request);
+	} else { // unknown type
+	    logger.error("cant handle request of type "+ type);
+	    
+	}
+	return response;
+    }
+
+    protected Element processSystemRequest(Element request) {
+
+	Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	response.setAttribute(GSXML.FROM_ATT, this.cluster_name);
+	response.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_SYSTEM);
+
+	// a list of system requests - should put any error messages
+	// or success messages into response
+	NodeList commands = request.getElementsByTagName(GSXML.SYSTEM_ELEM);
+	String message=null;	
+	for (int i=0; i<commands.getLength(); i++) {
+	    // all the commands should be Elements
+	    Element elem = (Element)commands.item(i);
+	    String action = elem.getAttribute(GSXML.TYPE_ATT);
+	    if (action.equals(GSXML.SYSTEM_TYPE_CONFIGURE)) {
+		String subset = elem.getAttribute(GSXML.SYSTEM_SUBSET_ATT);
+		if (subset.equals("")) {
+		    // need to reconfigure the service cluster
+		    
+		    if (this.configure()) {
+			Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, this.cluster_name + " reconfigured");
+			response.appendChild(s);
+			
+		    } else {
+			Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, this.cluster_name + " could not be reconfigured");
+			response.appendChild(s); 
+		    }
+		} else if (this.configureSubset(subset)) {
+		    Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, this.cluster_name + " "+subset+" reconfigured");
+		    response.appendChild(s);
+		} else {
+		    Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, this.cluster_name + " "+subset + " could not be reconfigured");
+		    response.appendChild(s); 
+		}
+		continue;
+	    } // configure action
+	    
+	    String module_name = elem.getAttribute(GSXML.SYSTEM_MODULE_NAME_ATT);
+	    String module_type = elem.getAttribute(GSXML.SYSTEM_MODULE_TYPE_ATT);
+	    if (action.equals(GSXML.SYSTEM_TYPE_ACTIVATE)) {
+		Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, "activate action not yet implemented - does it even make sense in this context??");
+		response.appendChild(s);
+	    } else if (action.equals(GSXML.SYSTEM_TYPE_DEACTIVATE)) {
+		if (module_type.equals(GSXML.SERVICE_ELEM)) {
+		    // deactivate the service
+		    // remove from service_map
+		    this.service_map.remove(module_name);
+		    Element service_elem = GSXML.getNamedElement(this.service_list, GSXML.SERVICE_ELEM, GSXML.NAME_ATT, module_name);
+		    service_list.removeChild(service_elem);		    
+		    message = module_type+": "+module_name+" deactivated";
+		} else {
+		    message = "can't deactivate "+module_type+" type modules!";}
+		Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, message);
+		response.appendChild(s);
+	    } else {
+		logger.error("cant process system request, action "+action);
+		continue;
+	    }
+	} // for each command
+	return response;
+    }
+
+    /** 
+     * do a configure on only part of the collection
+     */
+    protected boolean configureSubset(String subset) {
+	
+	File configFile = new File(GSFile.siteConfigFile(this.site_home));
+	if (!configFile.exists() ) {
+	    logger.error("site config file: "+configFile.getPath()+" not found!");
+	    // wont be able to do any of the requests
+	    return false;
+	    
+	}
+	
+	Document site_config_doc  = this.converter.getDOM(configFile);
+	if (site_config_doc == null) {
+	    logger.error("could not read in site config file: "+configFile.getPath());
+	    return false;
+	}
+	
+	Element site_config_elem = site_config_doc.getDocumentElement();
+	Element cluster_config_elem = GSXML.getNamedElement((Element)GSXML.getChildByTagName(site_config_elem, GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER), GSXML.CLUSTER_ELEM, GSXML.NAME_ATT, this.cluster_name);
+	if (cluster_config_elem == null) {
+	    logger.error("site config file: "+configFile.getPath()+" has no element for cluster "+this.cluster_name);
+	    // wont be able to do any of teh requests
+	    return false;
+	    
+	}
+	if (subset.equals(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER)) {
+	    Element service_rack_list = (Element)GSXML.getChildByTagName(cluster_config_elem, GSXML.SERVICE_CLASS_ELEM+GSXML.LIST_MODIFIER);
+	    
+	    return configureServiceRack(service_rack_list, null);
+	} else if (subset.equals(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER)) {
+	    this.metadata_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+	    Element metadata_list = (Element)GSXML.getChildByTagName(cluster_config_elem, GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+	    return addMetadata(metadata_list);
+	} else if (subset.equals(GSXML.PLUGIN_ELEM+GSXML.LIST_MODIFIER)) {
+	    this.plugin_item_list = this.doc.createElement(GSXML.PLUGIN_ELEM+GSXML.LIST_MODIFIER);
+	    Element import_list = (Element)GSXML.getChildByTagName(cluster_config_elem,GSXML.IMPORT_ELEM);
+	    if (import_list != null)
+	    {
+	    	Element plugin_item_list = (Element)GSXML.getChildByTagName(cluster_config_elem,GSXML.PLUGIN_ELEM+GSXML.LIST_MODIFIER);
+	    	return addPlugins(plugin_item_list);
+            }
+	    else
+	    	return false;
+	} else {
+	    logger.error("cannot process system request, configure "+subset);
+	    return false;
+	} 
+
+    } 
+
+
+    protected boolean addAllDisplayInfo(Element description, String lang) {
+	
+	NodeList items = this.display_item_list.getChildNodes();
+	for (int i=0; i<items.getLength(); i++) { // for each key
+	    Element m = (Element) items.item(i);
+	    // find the child with the correct language
+	    Element new_m = GSXML.getNamedElement(m, GSXML.DISPLAY_TEXT_ELEM, GSXML.LANG_ATT, lang);
+	    if (new_m==null && lang != DEFAULT_LANG) {
+		// use the default lang
+		new_m = GSXML.getNamedElement(m, GSXML.DISPLAY_TEXT_ELEM, GSXML.LANG_ATT, DEFAULT_LANG);
+	    }
+	    if (new_m==null) {
+		// just get the first one
+		new_m = (Element)GSXML.getChildByTagName(m, GSXML.DISPLAY_TEXT_ELEM);
+	    }
+	    description.appendChild(new_m.cloneNode(true));
+	}
+	return true;
+	
+    }
+
+    
+    protected Element getDisplayTextElement(String key, String lang) {
+	
+	Element this_item = GSXML.getNamedElement(this.display_item_list, GSXML.DISPLAY_TEXT_ELEM, GSXML.NAME_ATT, key);
+	if (this_item == null) {
+	    return null;
+	}
+
+	Element this_lang = GSXML.getNamedElement(this_item, GSXML.DISPLAY_TEXT_ELEM, GSXML.LANG_ATT, lang);
+	if (this_lang == null && lang != DEFAULT_LANG) {
+	    // try the default
+	    this_lang = GSXML.getNamedElement(this_item, GSXML.DISPLAY_TEXT_ELEM, GSXML.LANG_ATT, DEFAULT_LANG);
+	}
+	if (this_lang == null) {
+	    // just return the first one
+	    return (Element)this_item.getFirstChild().cloneNode(true);
+	}
+	return (Element)this_lang.cloneNode(true);
+	
+    }
+}
+
+
+
+
+
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/collection/XMLCollection.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/collection/XMLCollection.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/collection/XMLCollection.java	(revision 14125)
@@ -0,0 +1,129 @@
+package org.greenstone.gsdl3.collection;
+
+import org.greenstone.gsdl3.util.*;
+import org.greenstone.gsdl3.core.*;
+import org.greenstone.gsdl3.service.*;
+
+
+// java XML classes we're using
+import org.w3c.dom.Document; 
+import org.w3c.dom.Node; 
+import org.w3c.dom.Element; 
+import org.w3c.dom.NodeList; 
+
+import java.io.File;
+import java.util.HashMap;
+
+import org.apache.log4j.*;
+
+/* for a collection that hasn't been built with greenstone build stuff. expects a documentList in the collectionConfig file, and it stores this. this is where doc level metadata comes from */
+public class XMLCollection 
+    extends Collection {
+
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.collection.XMLCollection.class.getName());
+
+    protected Element document_list = null;
+    /** overwrite this to keep the document list
+     * find the metadata and display elems from the two config files and add it to the appropriate lists
+     */
+    protected boolean findAndLoadInfo(Element coll_config_xml, 
+				      Element build_config_xml){
+
+	// metadata
+	Element meta_list = (Element)GSXML.getChildByTagName(coll_config_xml, GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+	addMetadata(meta_list);
+	meta_list = (Element)GSXML.getChildByTagName(build_config_xml, GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+	addMetadata(meta_list);
+
+	meta_list = this.doc.createElement(GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER);
+	GSXML.addMetadata(this.doc, meta_list, "httpPath", this.site_http_address+"/collect/"+this.cluster_name);
+	addMetadata(meta_list);
+
+	// display stuff
+	Element display_list = (Element)GSXML.getChildByTagName(coll_config_xml, GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER);
+	if (display_list != null) {
+	    addDisplayItems(display_list);
+	}
+
+	//plugin stuff
+	Element import_list = (Element)GSXML.getChildByTagName(coll_config_xml, GSXML.IMPORT_ELEM);
+	if (import_list != null)
+	{
+		Element plugin_list = (Element)GSXML.getChildByTagName(import_list, GSXML.PLUGIN_ELEM+GSXML.LIST_MODIFIER);
+		addPlugins(plugin_list);
+	}
+	
+	Element config_doc_list = (Element)GSXML.getChildByTagName(coll_config_xml, GSXML.DOCUMENT_ELEM+GSXML.LIST_MODIFIER);
+	if (config_doc_list != null) {
+	    document_list = (Element)this.doc.importNode(config_doc_list, true);
+	} else {
+	    document_list = this.doc.createElement(GSXML.DOCUMENT_ELEM+GSXML.LIST_MODIFIER);
+	}
+	return true;
+
+    }
+
+    /** handles requests made to the ServiceCluster itself 
+     *
+     * @param req - the request Element- <request>
+     * @return the result Element - should be <response>
+     */
+    protected Element processMessage(Element request) {
+
+	Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	response.setAttribute(GSXML.FROM_ATT, this.cluster_name);
+	String type = request.getAttribute(GSXML.TYPE_ATT);
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	response.setAttribute(GSXML.TYPE_ATT, type);
+	
+	if (type.equals(GSXML.REQUEST_TYPE_DESCRIBE)) {
+	    // create the collection element
+	    Element description = (Element)this.description.cloneNode(false);
+	    response.appendChild(description);
+	    // check the param list
+	    Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	    if (param_list == null) {
+		addAllDisplayInfo(description, lang);
+		description.appendChild(this.service_list);
+		description.appendChild(this.metadata_list);
+		description.appendChild(this.plugin_item_list);
+		description.appendChild(this.document_list);
+		return response;
+	    }
+	    
+	    // go through the param list and see what components are wanted
+	    NodeList params = param_list.getElementsByTagName(GSXML.PARAM_ELEM);
+	    for (int i=0; i<params.getLength(); i++) {
+		
+		Element param = (Element)params.item(i);
+		// Identify the structure information desired
+		if (param.getAttribute(GSXML.NAME_ATT) == GSXML.SUBSET_PARAM ) {
+		    String info = param.getAttribute(GSXML.VALUE_ATT);
+		    if (info.equals(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER)) {
+			description.appendChild(this.service_list);
+		    } else if (info.equals(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER)) {
+			description.appendChild(metadata_list);
+		    } else if (info.equals(GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER)) {
+			addAllDisplayInfo(description, lang);
+			
+		    } else if (info.equals(GSXML.DOCUMENT_ELEM+GSXML.LIST_MODIFIER)) {
+			description.appendChild(this.document_list);
+		    } else if (info.equals(GSXML.PLUGIN_ELEM+GSXML.LIST_MODIFIER)) {
+		    	description.appendChild(this.plugin_item_list);
+		    }
+		    
+		}
+	    }
+	    return response;
+	}
+	
+	if (type.equals(GSXML.REQUEST_TYPE_SYSTEM)) {
+	    response = processSystemRequest(request);
+	} else { // unknown type
+	    logger.error("cant handle request of type "+ type);
+	    
+	}
+	return response;
+    }
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/comms/Communicator.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/comms/Communicator.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/comms/Communicator.java	(revision 14125)
@@ -0,0 +1,69 @@
+/*
+ *    Communicator.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.comms;
+
+import org.greenstone.gsdl3.core.ModuleInterface;
+import org.greenstone.gsdl3.util.*;
+
+//XML packages
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/** Communicator - base class for Modules that talk via some protocol to other modules
+ *
+ * can be used by a MessageRouter - in this case set localSiteName
+ * can be used by any other module - in this case it has no local site - dont set localsiteName. the setting of localSiteName affects the handling of teh to and from fields in the message. 
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @version $Revision$
+ */
+abstract public class Communicator
+    implements ModuleInterface {
+
+    /** name of local site */
+    protected String local_site_name_ = null;
+
+    /** name of site to connect to */
+    protected String remote_site_name_=null;
+
+    /** converter for String to DOM and vice versa */
+    protected XMLConverter converter_= null;
+
+    public Communicator() {
+	converter_ = new XMLConverter();
+    }
+    public void cleanUp() {}
+
+    public void setLocalSiteName(String name) {
+	local_site_name_ = name;
+    }
+    /** this should be done as part of configure */
+    public void setRemoteSiteName(String name) {
+	remote_site_name_ = name;
+    }
+    /** configures the Communicator using the <site> element */
+    abstract public boolean configure(Element site_elem); 
+
+    public String process(String xml_in) {
+	Element e = converter_.getDOM(xml_in).getDocumentElement();
+	Node result = process(e);
+	return converter_.getString(result);	
+    }
+
+    abstract public Element process(Element xml_in);
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/comms/SOAPCommunicator.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/comms/SOAPCommunicator.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/comms/SOAPCommunicator.java	(revision 14125)
@@ -0,0 +1,173 @@
+/*
+ *    SOAPCommunicator.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.comms;
+
+import org.greenstone.gsdl3.util.*;
+import org.greenstone.gsdl3.core.*;
+
+// classes needed for SOAP stuff
+import java.net.URL;
+import java.net.MalformedURLException;
+import java.util.Vector;
+import org.apache.axis.client.Call;
+import org.apache.axis.client.Service;
+import org.apache.axis.message.SOAPBodyElement;
+import javax.xml.namespace.QName;
+
+import org.w3c.dom.Node; 
+import org.w3c.dom.NodeList; 
+import org.w3c.dom.Document; 
+import org.w3c.dom.Element; 
+
+import org.apache.log4j.*;
+
+/*
+ * The Client side of a SOAP Connection
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @version $Revision$
+ * @see <a href="http://www.w3.org/TR/SOAP/">Simple Object Access Protocol (SOAP) 1.1 </a>
+ */
+public class SOAPCommunicator
+    extends Communicator {
+
+      static Logger logger = Logger.getLogger(org.greenstone.gsdl3.comms.SOAPCommunicator.class.getName());
+
+    /** address of site to connect to */
+    protected String remote_site_address_=null;
+
+    /** the call object that does the SOAP talking */
+    private Call call_ = null;
+
+  /** The no-args constructor */
+    public SOAPCommunicator() {
+	
+    }
+        
+    public boolean configure(Element site_elem) {
+	
+	String type = site_elem.getAttribute(GSXML.TYPE_ATT);
+	if (!type.equals(GSXML.COMM_TYPE_SOAP_JAVA)) {
+	    logger.error("wrong type of site");
+	    return false;
+	}
+	remote_site_name_ = site_elem.getAttribute(GSXML.NAME_ATT);
+	if (remote_site_name_.equals("")) {
+	    logger.error("must have name attribute in site element");
+	    return false;
+	}
+	remote_site_address_ = site_elem.getAttribute(GSXML.ADDRESS_ATT);
+	String local_site_name = site_elem.getAttribute(GSXML.LOCAL_SITE_ATT);
+	if (remote_site_address_.equals("") && local_site_name.equals("")) {
+	    logger.error("must have address or localSite attributes in site element");
+	    return false;
+	}
+	if (remote_site_address_.equals("")) {
+	    remote_site_address_ = GlobalProperties.getGSDL3WebAddress()+"/services/"+local_site_name;
+	}
+
+	try {
+	    Service service = new Service();
+	    call_ = (Call) service.createCall();
+	    call_.setTargetEndpointAddress( new java.net.URL(remote_site_address_) );
+	} catch (Exception e) {
+	    logger.error("SOAPCommunicator.configure() Error: Exception occurred "+e);
+	    return false;
+	}
+	return true;
+    }
+
+    public Element process(Element message) {
+	
+	NodeList requests = message.getElementsByTagName(GSXML.REQUEST_ELEM);
+	if (requests.getLength()==0) {
+	    // no requests
+	    return null;
+	}
+
+	// if the communicator is part of a site, it needs to edit the to and from fields, otherwise it just passes the message on, as is
+	// for now, use local_site_name_ as the flag.
+	if (local_site_name_!=null) { // no local site
+	    
+	    for (int i=0;i<requests.getLength(); i++) {
+		Element e = (Element)requests.item(i);
+		String to = e.getAttribute(GSXML.TO_ATT);
+		to = GSPath.removeFirstLink(to); // remove the server name, should check that it is present
+		e.setAttribute(GSXML.TO_ATT, to);
+		String from = e.getAttribute(GSXML.FROM_ATT);
+		from = GSPath.appendLink(from, local_site_name_);
+		e.setAttribute(GSXML.FROM_ATT, from);
+	    }
+	}
+	// else do nothing to the requests, just pass it on
+
+	// the soap impl needs a namespace for the top level element
+	Element message_to_send = message;
+	if (message.getNamespaceURI() == null) {
+	    message_to_send = GSXML.duplicateWithNewNameNS(message.getOwnerDocument(), message, "gs3:"+message.getTagName(), "urn:foo", true);
+	}
+	
+	// do the soap query
+	Element result = null;
+	try {
+	    SOAPBodyElement[] input = new SOAPBodyElement[1];
+	    input[0] = new SOAPBodyElement(message_to_send);
+	    Vector output = (Vector) call_.invoke( input );
+	    SOAPBodyElement elem = (SOAPBodyElement) output.get(0);
+	    result = elem.getAsDOM();
+	} catch (Exception e) {
+	    e.printStackTrace();
+	    return null;
+	}
+	
+	if (local_site_name_ != null) {// have to modify the from field
+	    
+	    NodeList responses = result.getElementsByTagName(GSXML.RESPONSE_ELEM);
+	    for (int i=0;i<responses.getLength(); i++) {
+		Element e = (Element)responses.item(i);
+		String from = e.getAttribute(GSXML.FROM_ATT);
+		from = GSPath.prependLink(from, remote_site_name_);
+		e.setAttribute(GSXML.FROM_ATT, from);
+	    }
+	} // else return as is
+	
+	return result;
+    }
+
+    public static void main (String [] args) {
+	SOAPCommunicator comm = new SOAPCommunicator();
+	XMLConverter converter = new XMLConverter();
+	String message = "<site name=\"localsite\" address=\"http://kanuka.cs.waikato.ac.nz:7070/axis/services/localsite\" type=\"soap\"/>";
+	Element site_elem = converter.getDOM(message).getDocumentElement();
+	comm.configure(site_elem);
+	message = "<message><request type=\"describe\" to=\"\" lang=\"en\"/></message>";
+	Element request_elem = converter.getDOM(message).getDocumentElement();
+	Element response = comm.process(request_elem);
+	
+	logger.error("response was "+converter.getPrettyString(response));
+    }
+}
+
+
+
+
+
+
+
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/core/DefaultReceptionist.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/core/DefaultReceptionist.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/core/DefaultReceptionist.java	(revision 14125)
@@ -0,0 +1,163 @@
+package org.greenstone.gsdl3.core;
+
+import org.greenstone.gsdl3.util.*;
+import org.greenstone.gsdl3.action.*;
+// XML classes
+import org.w3c.dom.Node; 
+import org.w3c.dom.NodeList; 
+import org.w3c.dom.Document; 
+import org.w3c.dom.Element; 
+
+// other java classes
+import java.io.File;
+import java.util.HashMap;
+import java.util.Enumeration;
+
+import org.apache.log4j.*;
+
+/** The default greenstone receptionist - needs some extra info for each page
+ */
+public class DefaultReceptionist extends TransformingReceptionist {
+
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.core.DefaultReceptionist.class.getName());
+    
+    protected void addExtraInfo(Element page) {
+	// we want to add in the collection description for each page - cos
+	// our default xslt needs this.
+	super.addExtraInfo(page);
+	
+	Element page_request = (Element)GSXML.getChildByTagName(page, GSXML.PAGE_REQUEST_ELEM);
+	// if it is a system request, then we don't bother with this.
+	String action = page_request.getAttribute(GSXML.ACTION_ATT);
+	if (action.equals("s")) {
+	    logger.error("HACK: don't ask for coll info if system action");
+	    return;
+	}
+	logger.debug("add extra info, page request="+this.converter.getString(page_request));
+	// is a collection defined?
+	Element param_list = (Element)GSXML.getChildByTagName(page_request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (param_list==null) { // must be the original home page
+	    logger.debug(" no param list, assuming home page");
+	    return;
+	}
+	Element coll_param = GSXML.getNamedElement(param_list, GSXML.PARAM_ELEM, GSXML.NAME_ATT, GSParams.COLLECTION);
+	if (coll_param == null) {
+	    logger.debug(" coll param is null, returning");
+	    return;
+	}
+
+	// see if the collection/cluster element is already there
+	String coll_name = coll_param.getAttribute(GSXML.VALUE_ATT);
+	String lang = page_request.getAttribute(GSXML.LANG_ATT);
+	String uid = page_request.getAttribute(GSXML.USER_ID_ATT);
+	
+	boolean get_service_description = false;
+	Element page_response = (Element)GSXML.getChildByTagName(page, GSXML.PAGE_RESPONSE_ELEM);
+	if (this.language_list != null) {
+	    page_response.appendChild(this.language_list);
+	}
+	Element coll_description = (Element)GSXML.getChildByTagName(page_response, GSXML.COLLECTION_ELEM);
+	if (coll_description == null) {
+	    // try cluster
+	    coll_description = (Element)GSXML.getChildByTagName(page_response, GSXML.CLUSTER_ELEM);
+	}
+	if (coll_description == null) { 
+	    // we dont have one yet - get it
+	    Element coll_about_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	    Element coll_about_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE,  coll_name, lang, uid);
+	    coll_about_message.appendChild(coll_about_request);
+	    
+	    Element coll_about_response_message = this.mr.process(coll_about_message);
+	    Element coll_about_response = (Element)GSXML.getChildByTagName(coll_about_response_message, GSXML.RESPONSE_ELEM);
+	    if (coll_about_response == null) {
+		return;
+	    }
+	    coll_description = (Element)GSXML.getChildByTagName(coll_about_response, GSXML.COLLECTION_ELEM);
+	    if (coll_description==null) { // may be a cluster
+		coll_description = (Element)GSXML.getChildByTagName(coll_about_response, GSXML.CLUSTER_ELEM);
+	    }
+	    
+	    if (coll_description == null) {
+		logger.error(" no collection description, returning");
+		return;
+	    }
+	    // have found one, append it to the page response
+	    coll_description = (Element)this.doc.importNode(coll_description, true);
+	    page_response.appendChild(coll_description);
+	    get_service_description = true;
+	}
+
+	// have got a coll description
+	
+	// now get the dispay info for the services
+	Element service_list = (Element)GSXML.getChildByTagName(coll_description, GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER);
+	if (service_list == null) {
+	    logger.error(" no service list, returning");
+	    // something weird has gone wrong
+	    return;
+	}
+
+	NodeList services = service_list.getElementsByTagName(GSXML.SERVICE_ELEM);
+	if (services.getLength()==0) {
+	    logger.error("DefaultReceoptionist: no services found for colllection/cluster "+ coll_name);
+	    return;
+	}
+	// check one service for display items
+	if (!get_service_description) {
+	    // we dont know yet if we need to get these
+	    int i=1;
+	    Element test_s = (Element)services.item(0);
+	    while (i<services.getLength() && test_s.getAttribute(GSXML.TYPE_ATT).equals(GSXML.SERVICE_TYPE_RETRIEVE)) {
+		test_s = (Element)services.item(i); i++;
+	    }
+	    if (i==services.getLength()) {
+		// we have only found retrieve services, so dont need descripitons anyway
+		return;
+	    }
+	    if (GSXML.getChildByTagName(test_s, GSXML.DISPLAY_TEXT_ELEM) !=null) {
+		// have got descriptions already, 
+		return;
+	    }
+	}
+
+	// if get here, we need to get the service descriptions
+	logger.debug("getting services description");
+	    
+	// we will send all the requests in a single message
+	Element info_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	for (int i=0; i<services.getLength(); i++) {
+	    Element c = (Element)services.item(i);
+	    String name = c.getAttribute(GSXML.NAME_ATT);
+	    String address = GSPath.appendLink(coll_name, name);
+	    Element info_request = GSXML.createBasicRequest(this.doc,  GSXML.REQUEST_TYPE_DESCRIBE, address, lang, uid);
+	    Element req_param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	    req_param_list.appendChild(GSXML.createParameter(this.doc, GSXML.SUBSET_PARAM, GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER));
+	    info_request.appendChild(req_param_list);
+	    info_message.appendChild(info_request);
+	    
+	}
+
+	Element info_response = (Element)this.mr.process(info_message);
+
+	NodeList service_responses = info_response.getElementsByTagName(GSXML.RESPONSE_ELEM);
+	// check that have same number of responses as collections
+	if (services.getLength() != service_responses.getLength()) {
+	    logger.error(" didn't get a response for each service - somethings gone wrong!");
+	    // for now, dont use the metadata
+	} else {
+	    for (int i=0; i<services.getLength(); i++) {
+		Element c1 = (Element)services.item(i);
+		Element c2 = (Element)GSXML.getChildByTagName((Element)service_responses.item(i), GSXML.SERVICE_ELEM);
+		if (c1 !=null && c2 !=null && c1.getAttribute(GSXML.NAME_ATT).equals(c2.getAttribute(GSXML.NAME_ATT))) {
+		    //add the service data into the original response
+		    GSXML.mergeElements(c1, c2);
+		} else {
+		    logger.error(" response does not correspond to request!");
+		} 
+		
+	    }
+	}
+	
+    }
+}
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/core/GSException.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/core/GSException.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/core/GSException.java	(revision 14125)
@@ -0,0 +1,50 @@
+/*
+ *    GSException.java
+ *    a new exception for Greenstone
+
+ *    Copyright (C) 2005 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.core;
+
+import org.greenstone.gsdl3.util.GSXML;
+
+public class GSException
+    extends Exception {
+
+    private String exception_type = null;
+    // need some better names for these
+    //public static int PERMANENT = 0;
+    //public static int TEMPORARY = 1;
+    //public static int OTHER = 2;
+
+    public GSException(String message) {
+	
+	super(message);
+	this.exception_type = GSXML.ERROR_TYPE_OTHER;
+    }
+    public GSException(String message, String type) {
+
+	super(message);
+	this.exception_type = type;
+    }
+
+    public String getType() {
+	return exception_type;
+    }
+	
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/core/MessageRouter.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/core/MessageRouter.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/core/MessageRouter.java	(revision 14125)
@@ -0,0 +1,943 @@
+/*
+ *    MessageRouter.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.core;
+
+import org.greenstone.gsdl3.util.*;
+import org.greenstone.gsdl3.service.*;
+import org.greenstone.gsdl3.comms.*;
+import org.greenstone.gsdl3.collection.*;
+
+// XML classes
+import org.w3c.dom.Node; 
+import org.w3c.dom.NodeList; 
+import org.w3c.dom.Document; 
+import org.w3c.dom.Element; 
+import org.xml.sax.InputSource;
+import javax.xml.parsers.*;
+
+// other java classes
+import java.io.File;
+import java.io.Reader;
+import java.io.StringReader;
+import java.net.Authenticator;
+import java.net.PasswordAuthentication;      
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Properties;
+
+import org.apache.log4j.*;
+
+/**
+ * The hub of a Greenstone system. 
+ *
+ * Accepts  XML requests (via process method of ModuleInterface) and routes them to the appropriate collection or 
+ * service or external entity.
+ *
+ * contains a map of module objects - may be services, collections, comms 
+ * objects talking to other MessageRouters etc.
+ *
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @version $Revision$
+ * @see ModuleInterface
+ * @see Collection
+ * @see ServiceRack
+ * @see Communicator
+ *
+ */
+public class MessageRouter implements  ModuleInterface {
+
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.core.MessageRouter.class.getName());
+
+    /** the (directory) name of the site */
+    protected String site_name = null;
+    /** site home - the home directory for the site */
+    protected String site_home=null;
+    /** the http address for this site */
+    protected String site_http_address=null;
+    
+    /** map of names to Module objects */
+    protected HashMap module_map=null;
+
+    /** container Document to create XML Nodes */
+    protected Document doc=null; 
+    /** the full description of this site */
+
+    // should these things be separated into local and remote??
+
+    /** the original xml config element */
+    public Element config_info = null;
+
+    /** list of collections that can be reached */
+    protected Element collection_list = null; 
+    /** list of service clusters that can be reached */
+    protected Element cluster_list = null; 
+    /** list of single services that can be reached */
+    protected Element service_list = null; 
+    /** list of sites that can be reached */
+    protected Element site_list = null; 
+    
+   
+    /** a converter class to parse XML and create Docs */
+    protected XMLConverter converter=null;
+
+    //***************************************************************
+    // public methods
+    //***************************************************************
+
+    /** constructor */
+    public MessageRouter() {
+	this.converter = new XMLConverter();
+	this.doc = this.converter.newDOM();
+    }
+
+    public void cleanUp() {
+	if (this.module_map != null) {
+	    Iterator i = this.module_map.values().iterator();
+	    while (i.hasNext()) {
+		((ModuleInterface)i.next()).cleanUp();
+	    }
+	}
+    }
+
+    /** site_name must be set before configure is called */
+    public void setSiteName(String site_name) {
+	this.site_name = site_name;
+    }
+    /**
+     * configures the system
+     *
+     * looks in site_home/collect for collections, reads config file
+     * site_home/siteConfig.xml
+     *
+     */
+    public boolean configure() { 
+
+	logger.info("configuring site");
+
+	if (this.site_name==null) {
+	    logger.error(" You must set site_name before calling configure");
+	    return false;
+	}
+	this.site_home = GSFile.siteHome(GlobalProperties.getGSDL3Home(), this.site_name);
+	this.site_http_address = GlobalProperties.getGSDL3WebAddress()+"/sites/"+this.site_name;
+	
+	// are we behind a firewall?? - is there a better place to set up the proxy?
+	String host = GlobalProperties.getProperty("proxy.host");
+	String port = GlobalProperties.getProperty("proxy.port");
+	final String user = GlobalProperties.getProperty("proxy.user");
+	final String passwd = GlobalProperties.getProperty("proxy.password");
+	  
+	if (host != null && !host.equals("") && port !=null && !port.equals("")) {
+	    System.setProperty("http.proxyType", "4");
+	    System.setProperty("http.proxyHost", host);
+	    System.setProperty("http.proxyPort", port);
+	    System.setProperty("http.proxySet", "true");
+	    // have we got a user/password?
+	    if (user != null && !user.equals("") && passwd != null && !passwd.equals("")) {
+		try {
+		    // set up the authenticator
+		    Authenticator.setDefault(new Authenticator(){ 
+			    protected PasswordAuthentication getPasswordAuthentication(){ 
+				return new PasswordAuthentication(user, new String(passwd).toCharArray()); 
+			    } 
+			}); 
+		    
+		} catch (Exception e) {
+		    logger.error("MessageRouter Error: couldn't set up an authenticator the proxy");
+		    
+		}
+	    }
+	}
+
+	// read thru own config file - create services and connect to sites
+	File configFile = new File(GSFile.siteConfigFile(this.site_home));
+
+	if (!configFile.exists() ) {
+	    logger.error(" site config file: "+configFile.getPath()+" not found!");
+	    return false;
+	}
+	
+	Document config_doc = this.converter.getDOM(configFile);
+	if (config_doc == null) {
+logger.error(" couldn't parse site config file: "+configFile.getPath());
+	    return false;
+	}
+	
+	config_info = config_doc.getDocumentElement();
+	
+	this.module_map = new HashMap();
+	
+	// load up the services
+	Element service_rack_list = (Element)GSXML.getChildByTagName(config_info, GSXML.SERVICE_CLASS_ELEM+GSXML.LIST_MODIFIER);
+	configureServices(service_rack_list);
+	
+	// load up the service clusters
+	Element cluster_list = (Element)GSXML.getChildByTagName(config_info, GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER);	
+	configureClusters(cluster_list);
+
+	// load up the collections
+	configureCollections();
+
+	// load up the external sites - this also adds their services/clusters/collections to the other lists - so must be done last
+	Element site_list = (Element)GSXML.getChildByTagName(config_info, GSXML.SITE_ELEM+GSXML.LIST_MODIFIER);
+	configureSites(site_list);
+	
+		
+	return true;
+	
+    }
+ 	
+   
+    /**
+     * Process an XML request - as a String
+     *
+     * @param xml_in the request to process
+     * @return the response - contains any error messages
+     * @see String
+     */
+    public String process(String xml_in) {
+	
+	Document doc = this.converter.getDOM(xml_in);
+	
+	Element result = process(doc.getDocumentElement());
+	return this.converter.getString(result);
+    }
+    
+    /**
+     * Process an XML request - as a DOM Element
+     *
+     * @param xml_in the message to process - should be <message>
+     * @return the response - contains any error messages
+     * @see Element
+     */
+    public Element process(Element message) {
+     
+	logger.debug("MR received request");
+	logger.debug(this.converter.getString(message));
+	// check that its a correct message tag
+	if (!message.getTagName().equals(GSXML.MESSAGE_ELEM)) {
+	    logger.error(" Invalid message. GSDL message should start with <"+GSXML.MESSAGE_ELEM+">, instead it starts with:"+message.getTagName()+".");
+	    return null;
+	}
+
+	NodeList requests = message.getElementsByTagName(GSXML.REQUEST_ELEM);
+
+	Element mainResult = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	
+	// empty request
+	if (requests.getLength()==0) {
+	    return mainResult;
+	}
+
+	Document message_doc = message.getOwnerDocument();
+
+	// for now, just process each request one by one, and append the results to mainResult
+	// Note: if you add an element to another node in the same document, it
+	// gets removed from where it was. This changes the node list - you cant iterate over the node list in a normal manner if you are moving elements out of it
+	int num_requests = requests.getLength();
+	for (int i=0; i< num_requests; i++) {
+	    Node result=null;
+	    Element req = (Element)requests.item(i);
+	    if (req == null) {
+		logger.error("request "+i+" is null");
+		continue;
+	    }
+	    String path = req.getAttribute(GSXML.TO_ATT); // returns "" if no att of this name
+	    if (path.equals("")) {
+		// its a message for the message router
+		if (req.getAttribute(GSXML.TYPE_ATT).equals(GSXML.REQUEST_TYPE_MESSAGING)) {
+		    // its a messaging request - modifies the requests/responses
+		    result = modifyMessages(req, message, mainResult);
+		    mainResult.appendChild(this.doc.importNode(result, true));
+		} else {
+		    // standard request
+		    result = processMessage(req);
+		    mainResult.appendChild(this.doc.importNode(result, true));
+		}
+	    } else {
+		String [] modules = path.split(",");
+		
+		for (int j=0; j<modules.length; j++) {
+		    // why can't we do this outside the loop??
+		    Element mess = this.doc.createElement(GSXML.MESSAGE_ELEM);
+		    Element copied_request = (Element)this.doc.importNode(req, true);
+		    mess.appendChild(copied_request);
+
+		    String this_mod = modules[j];
+		    // find the module to pass it on to
+		    // need to put the request into a message element
+		    String obj = GSPath.getFirstLink(this_mod);
+		    
+		    if (this.module_map.containsKey(obj)) {
+			copied_request.setAttribute(GSXML.TO_ATT, this_mod);
+			result = ((ModuleInterface)this.module_map.get(obj)).process(mess);
+			if (result !=null ) {
+			    // append the contents of the message to the mainResult - there will only be one response at this stage
+                            Node res = GSXML.getChildByTagName(result, GSXML.RESPONSE_ELEM);
+                            if (res != null){
+				mainResult.appendChild(this.doc.importNode(res, true));
+			    }
+			} else {
+			    // add in a place holder response
+			    Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+			    response.setAttribute(GSXML.FROM_ATT, this_mod);
+			    mainResult.appendChild(response);
+			    logger.error("MessageRouter Error: request had null result!");
+			}
+			
+		    } else {    
+			logger.error("MessageRouter Error: request has illegal module name in:\n"+this.converter.getString(req));
+		    }
+		}
+	    }
+	    
+	} // for each request
+	
+	logger.debug("MR returned response");
+	logger.debug(this.converter.getString(mainResult));
+
+	return mainResult;
+	
+    }
+	
+    // ********************************************************************
+    // auxiliary configure methods
+    // *******************************************************************
+
+
+    protected boolean configureServices(Element service_rack_list) {
+
+	this.service_list = this.doc.createElement(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER);
+
+	// load up the individual services
+	logger.info("loading service modules...");
+	
+	if (service_rack_list == null) {
+	    logger.info("... none to be loaded");
+	    return true;
+	} 
+	
+	NodeList service_racks = service_rack_list.getElementsByTagName(GSXML.SERVICE_CLASS_ELEM);
+	if (service_racks.getLength()==0) {
+	    logger.info("... none to be loaded");
+	    return true;
+	} 
+		
+	Element service_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element service_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, "", "", "");
+	service_message.appendChild(service_request);
+		
+	for(int i=0; i<service_racks.getLength(); i++) {
+	    Element n = (Element)service_racks.item(i);
+	    String service_name = n.getAttribute(GSXML.NAME_ATT);
+	    logger.info("..."+service_name);
+	    try {
+		ServiceRack s = (ServiceRack)Class.forName("org.greenstone.gsdl3.service."+service_name).newInstance();
+		s.setSiteHome(this.site_home);
+		s.setSiteAddress(this.site_http_address);
+		s.setMessageRouter(this);
+		// pass the XML node to the service for service configuration
+		s.configure(n, null);
+
+		// find out the supported services for this service module
+		Element service_response = (Element) s.process(service_message);
+		NodeList services = service_response.getElementsByTagName(GSXML.SERVICE_ELEM);
+		if (services.getLength()==0) {
+		    logger.error("MessageRouter configure error: serviceRack "+service_name+" has no services!");
+		} else {
+		    for (int j=0; j<services.getLength();j++) {
+			String service = ((Element)services.item(j)).getAttribute(GSXML.NAME_ATT);
+			this.module_map.put(service, s);
+			
+				// add short info to service_list_ XML
+			this.service_list.appendChild(this.doc.importNode(services.item(j), true));
+		    }
+		}
+	    } catch (Exception e ) {
+		logger.error("MessageRouter configure exception:  in ServiceRack class specification:  "+ e.getMessage());
+		e.printStackTrace();
+	    } 
+	} // for each service module
+	return true;
+    }
+    
+    protected boolean configureClusters(Element config_cluster_list) {
+
+	this.cluster_list = this.doc.createElement(GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER);
+	// load up the service clusters
+	logger.info("loading service clusters ...");
+	if (config_cluster_list == null) {
+	    logger.info("... none to be loaded");
+	    return true;
+	} 
+	NodeList service_clusters = config_cluster_list.getElementsByTagName(GSXML.CLUSTER_ELEM);
+	if (service_clusters.getLength()==0) {
+	    logger.info("... none to be loaded");
+	    return true;
+	}
+	
+	for (int i=0; i<service_clusters.getLength(); i++) {
+	    Element cluster = (Element)service_clusters.item(i);
+	    String name = cluster.getAttribute(GSXML.NAME_ATT);
+	    logger.info("..."+name);
+	    ServiceCluster sc = new ServiceCluster();
+	    sc.setSiteHome(this.site_home);
+	    sc.setSiteAddress(this.site_http_address);
+	    sc.setClusterName(name);
+	    sc.setMessageRouter(this);
+	    sc.configure(cluster);
+	    this.module_map.put(name, sc); // this replaces the old one if there was one already present
+	    //add short info to cluster list
+	    Element e = this.doc.createElement(GSXML.CLUSTER_ELEM);
+	    e.setAttribute(GSXML.NAME_ATT, name);
+	    this.cluster_list.appendChild(e);
+	    
+	}
+	return true;
+    }
+    
+    protected boolean configureCollections() {
+
+	this.collection_list = this.doc.createElement(GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER);
+
+	// read thru the collect directory and activate all the valid collections
+	File collectDir = new File(GSFile.collectDir(this.site_home));
+	if (collectDir.exists()) {
+	    logger.info("Reading thru directory "+collectDir.getPath()+" to find collections.");
+	    File[] contents = collectDir.listFiles();
+	    for (int i=0; i<contents.length;i++) {
+		if(contents[i].isDirectory()) {
+		    
+		    String colName = contents[i].getName();
+		    if (!colName.startsWith("CVS")) {
+			activateCollectionByName(colName);
+		    }
+		}
+	    }
+	} // collectDir
+	return true;
+    }
+
+    protected boolean configureSites(Element config_site_list) {
+
+	this.site_list = this.doc.createElement(GSXML.SITE_ELEM+GSXML.LIST_MODIFIER);
+	// load up the sites
+	logger.info("loading external sites...");
+	if (config_site_list ==null ) {
+	    logger.info("...none found");
+	    return true;
+	}
+
+	NodeList sites = config_site_list.getElementsByTagName(GSXML.SITE_ELEM);
+	if (sites.getLength()==0) {
+	    logger.info("...none found");
+	    return true;
+	}
+
+	// this is a name to identify the current site in the Communicator 
+	String local_site_name = config_site_list.getAttribute(GSXML.LOCAL_SITE_NAME_ATT);
+	if (local_site_name.equals("")) {
+	    local_site_name = site_name;
+	}
+
+	for (int i=0; i<sites.getLength(); i++) {
+	    Element s = (Element)sites.item(i);
+	    activateSite(s, local_site_name);	    
+	}
+	return true;
+    }
+    
+    protected boolean activateSite(Element site_elem, String local_site_name) {
+	Communicator comm=null;
+	String type = site_elem.getAttribute(GSXML.TYPE_ATT);
+	String name = site_elem.getAttribute(GSXML.NAME_ATT);
+	if (type.equals(GSXML.COMM_TYPE_SOAP_JAVA)) {
+	    comm = new SOAPCommunicator();
+	    if (comm.configure(site_elem)) {
+		comm.setLocalSiteName(local_site_name);
+		
+		// add to map of modules
+		this.module_map.put(name, comm);
+		this.site_list.appendChild(this.doc.importNode(site_elem, true));
+		// need to get collection list and service 
+		// list from here- if the site isn't up yet, the site will
+		// have to be added later 
+		if (!getRemoteSiteInfo(comm, name)) {
+		    logger.error(" couldn't get info from site "+name);
+		}
+	    } else {
+		logger.error(" couldn't configure soap site:"+name);
+		return false;
+	    }
+	    
+	} else {
+	    System.err.print(" cant talk to server of type:"+type + ", so not making a connection to "+name);
+	    return false;
+	}
+	return true;
+    }
+    
+    /** get site info from external site
+     *
+     * @param comm - the communicator object for the external site
+     * @param site_name - the name of the external site
+     * @return true if successful
+     */
+    protected boolean getRemoteSiteInfo(Communicator comm, String site_name) {
+    
+	logger.info(" getting info from site:"+site_name);
+
+	Element info_request = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element req = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, "", "", "");
+	info_request.appendChild(req);
+
+	// process the message
+	Element info_response = comm.process(info_request);
+	if (info_response == null) {
+	    return false;
+	}
+	// collection info
+	NodeList colls = info_response.getElementsByTagName(GSXML.COLLECTION_ELEM);
+	if (colls.getLength()>0) {
+	    for (int i=0; i<colls.getLength(); i++) {
+		Element e = (Element)colls.item(i);
+		String col_name = e.getAttribute(GSXML.NAME_ATT);
+		// add the info to own coll list - may want to keep 
+		// this separate in future - so can distinguish own and 
+		// other collections ??
+		e.setAttribute(GSXML.NAME_ATT, GSPath.prependLink(col_name, site_name));
+		this.collection_list.appendChild(this.doc.importNode(e, true));
+	    }
+	}
+
+	// service info
+	NodeList services = info_response.getElementsByTagName(GSXML.SERVICE_ELEM);
+	if (services.getLength()>0) {
+	    for (int i=0; i<services.getLength(); i++) {
+		Element e = (Element)services.item(i);
+		String serv_name = e.getAttribute(GSXML.NAME_ATT);
+		e.setAttribute(GSXML.NAME_ATT, GSPath.prependLink(serv_name, site_name));
+		this.service_list.appendChild(this.doc.importNode(e, true));
+	    }
+	}
+	
+	// serviceCluster info
+	NodeList clusters = info_response.getElementsByTagName(GSXML.CLUSTER_ELEM);
+	if (clusters.getLength()>0) {
+	    for (int i=0; i<clusters.getLength(); i++) {
+		Element e = (Element)clusters.item(i);
+		String clus_name = e.getAttribute(GSXML.NAME_ATT);
+		e.setAttribute(GSXML.NAME_ATT, GSPath.prependLink(clus_name, site_name));
+		this.cluster_list.appendChild(this.doc.importNode(e, true));
+	    }
+	}
+	return true;
+    }
+
+
+    //*****************************************************************
+    // auxiliary process methods
+    //*****************************************************************
+
+    /** handles requests made to the MessageRouter itself 
+     *
+     * @param req - the request Element- <request>
+     * @return the result Element - should be <response>
+     */
+    protected Element processMessage(Element req) {
+
+	// message for self, should be type=describe/configure at this stage
+	String type = req.getAttribute(GSXML.TYPE_ATT);
+	Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	response.setAttribute(GSXML.FROM_ATT, "");
+	if (type.equals(GSXML.REQUEST_TYPE_DESCRIBE)) {
+	    response.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_DESCRIBE);
+	    // check the param list
+	    Element param_list = (Element) GSXML.getChildByTagName(req, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	    if (param_list == null) {
+		response.appendChild(this.collection_list);
+		response.appendChild(this.cluster_list);
+		response.appendChild(this.site_list);
+		response.appendChild(this.service_list);
+		return response;
+	    }
+	    NodeList params = param_list.getElementsByTagName(GSXML.PARAM_ELEM);
+	    
+	    // go through the param list and see what components are wanted
+	    for (int i=0; i<params.getLength(); i++) {
+		
+		Element param = (Element)params.item(i);
+		// Identify the structure information desired
+		if (param.getAttribute(GSXML.NAME_ATT).equals(GSXML.SUBSET_PARAM)) {
+		    String info = param.getAttribute(GSXML.VALUE_ATT);
+		    if (info.equals(GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER)) {
+			response.appendChild(this.collection_list);
+			
+		    } else if (info.equals(GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER)) {
+			response.appendChild(this.cluster_list);
+			
+		    } else if (info.equals(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER)) {
+			response.appendChild(this.service_list);
+		    } else if (info.equals(GSXML.SITE_ELEM+GSXML.LIST_MODIFIER)) {
+			response.appendChild(this.site_list);
+		    } 
+		}
+	    }
+	    return response;
+	    
+	} 
+	
+	if (type.equals(GSXML.REQUEST_TYPE_SYSTEM)) {
+	    
+	    // a list of system requests - should put any error messages
+	    // or success messages into response
+	    NodeList commands = req.getElementsByTagName(GSXML.SYSTEM_ELEM);
+	    Element site_config_elem = null;
+	    boolean success = false;
+			
+	    for (int i=0; i<commands.getLength(); i++) {
+		// all the commands should be Elements
+		Element elem = (Element)commands.item(i);
+		String action = elem.getAttribute(GSXML.TYPE_ATT);
+		if (action.equals(GSXML.SYSTEM_TYPE_CONFIGURE)) {
+		    String subset = elem.getAttribute(GSXML.SYSTEM_SUBSET_ATT);
+		    if (subset.equals("")) {
+			// need to reconfigure the MR
+			this.configure();
+			Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM,  "MessageRouter reconfigured successfully");
+			response.appendChild(s);
+			
+		    } else {
+			// else it a specific request
+			if (subset.equals(GSXML.COLLECTION_ELEM+GSXML.LIST_MODIFIER)) {
+			    success = configureCollections();
+			} else {
+
+			    // need the site config file
+			    if (site_config_elem==null) {
+				
+				File configFile = new File(GSFile.siteConfigFile(this.site_home));
+				if (!configFile.exists() ) {
+				    logger.error(" site config file: "+configFile.getPath()+" not found!");
+				    continue;
+				}
+				Document site_config_doc = this.converter.getDOM(configFile);
+				if (site_config_doc == null) {
+				    logger.error(" couldn't parse site config file: "+configFile.getPath());
+				    continue;
+				}
+				site_config_elem  = site_config_doc.getDocumentElement();
+			    }
+			    if (subset.equals(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER)) {
+				Element service_rack_list = (Element)GSXML.getChildByTagName(site_config_elem, GSXML.SERVICE_CLASS_ELEM+GSXML.LIST_MODIFIER);
+				
+				success = configureServices(service_rack_list);
+			    } else if (subset.equals(GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER)) {
+				Element cluster_list = (Element)GSXML.getChildByTagName(site_config_elem, GSXML.CLUSTER_ELEM+GSXML.LIST_MODIFIER);	
+				
+				success = configureClusters(cluster_list);
+			    } else if (subset.equals(GSXML.SITE_ELEM+GSXML.LIST_MODIFIER)) {
+				Element site_list = (Element)GSXML.getChildByTagName(site_config_elem, GSXML.SITE_ELEM+GSXML.LIST_MODIFIER);
+				success = configureSites(site_list);
+			    }
+			}
+			String message=null;
+			if (success) {
+			    message = subset + "reconfigured successfully";
+			} else {
+			    message = "Error in reconfiguring "+subset;
+			}
+			Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, message);
+			response.appendChild(s);
+		    }
+		    
+		    
+		} else {
+		    String module_name = elem.getAttribute(GSXML.SYSTEM_MODULE_NAME_ATT);
+		    String module_type = elem.getAttribute(GSXML.SYSTEM_MODULE_TYPE_ATT);
+
+		    if (action.equals(GSXML.SYSTEM_TYPE_DEACTIVATE)) {
+			deactivateModule(module_type, module_name);
+			Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, module_type+": "+module_name+" deactivated");
+			response.appendChild(s);
+		    } else if (action.equals(GSXML.SYSTEM_TYPE_ACTIVATE)) {
+			if (module_type.equals(GSXML.COLLECTION_ELEM)) {
+			    success = activateCollectionByName(module_name);
+			} else if (module_type.equals(GSXML.SITE_ELEM)) {
+			    success = activateSiteByName(module_name);
+			} else if (module_type.equals(GSXML.CLUSTER_ELEM)) {
+			    success = activateServiceClusterByName(module_name);
+			}
+			if (success) {
+			    Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, module_type+": "+module_name+" activated");
+			    response.appendChild(s);
+			} else {
+			    Element s = GSXML.createTextElement(this.doc, GSXML.STATUS_ELEM, module_type+": "+module_name+" could not be activated");
+			    response.appendChild(s);
+			}
+		    }
+		} // else not a configure action
+	    } // for all commands
+	    return response;
+			
+
+	} // system type request
+	
+	// if get here something has gone wrong
+	logger.error(" cant process request:");
+	logger.error(this.converter.getString(req));
+	return null;
+       
+    }
+    protected Element modifyMessages(Element request, Element message, Element result) {
+	Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	response.setAttribute(GSXML.FROM_ATT, "");
+	response.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_MESSAGING);
+
+	NodeList commands = request.getElementsByTagName("command");
+	if (commands == null) {
+	    logger.error("no commands, "+converter.getPrettyString(request));
+	    return response;
+	}
+	for (int i=0; i<commands.getLength(); i++) {
+	    Element action = (Element)commands.item(i);
+	    String type = action.getAttribute(GSXML.TYPE_ATT);
+	    if (type.equals("copyNode")) {
+		// copies the from node as a child of to node
+		String from_path = action.getAttribute("from");
+		String to_path = action.getAttribute("to");
+		Element from_node = null;
+		String from_node_root = GSPath.getFirstLink(from_path);
+		if (from_node_root.startsWith(GSXML.REQUEST_ELEM)) {
+		    from_node = message;
+		} else if (from_node_root.startsWith(GSXML.RESPONSE_ELEM)) {
+		    from_node = result;
+		}
+		if (from_node == null) {
+		    continue;
+		}
+		Element to_node = null;
+		String to_node_root = GSPath.getFirstLink(to_path);
+		if (to_node_root.startsWith(GSXML.REQUEST_ELEM)) {
+		    to_node = message;
+		} else if (to_node_root.startsWith(GSXML.RESPONSE_ELEM)) {
+		    to_node = result;
+		}
+		if (to_node == null) {
+		    continue;
+		}
+		// now we know what node to copy where
+		Node orig_node = GSXML.getNodeByPathIndexed(from_node, from_path);
+		if (orig_node == null) {
+		    continue;
+		}
+		Node new_parent = GSXML.getNodeByPathIndexed(to_node, to_path);
+		if (new_parent == null) {
+		    continue;
+		    
+		}
+		new_parent.appendChild(to_node.getOwnerDocument().importNode(orig_node, true));
+	    }
+	    
+	    else if (type.equals("copyChildren")) {
+
+	    }
+	} // for each command
+	return response;
+    }
+    
+    // ****************************************************
+    // other methods
+    // ****************************************************
+
+    /** creates and configures a new collection
+     *
+     *@param col_name the name of the collection
+     *@return true if collection created ok
+     */
+    protected boolean activateCollectionByName(String col_name) {
+
+	logger.info("Activating collection: "+col_name+".");
+
+	// Look for the etc/collectionInit.xml file, and see what sort of Collection to load
+	Collection c = null;
+	File init_file = new File(GSFile.collectionInitFile(this.site_home, col_name));
+
+	if (init_file.exists()) {
+	    Document init_doc = this.converter.getDOM(init_file);
+	    if (init_doc != null) {
+		Element init_elem = init_doc.getDocumentElement();
+		if (init_elem != null) {
+		    String coll_class_name = init_elem.getAttribute("class");
+		    if (!coll_class_name.equals("")) {
+			try {
+			    c = (Collection)Class.forName("org.greenstone.gsdl3.collection."+coll_class_name).newInstance();
+			} catch (Exception e) {
+			    logger.info(" couldn't create a new collection, type "+coll_class_name+", defaulting to class Collection");
+			}
+		    }
+		}
+	    }
+	}
+	if (c==null) { // we haven't found another classname to use
+	    c = new Collection();
+	}
+	
+	c.setCollectionName(col_name);
+	c.setSiteHome(this.site_home);
+	c.setSiteAddress(this.site_http_address);
+	c.setMessageRouter(this);
+	if (c.configure()) {
+	    // this could be a reactivation, so delete the old version
+	    deactivateModule(GSXML.COLLECTION_ELEM, col_name);
+	    // add to list of collections
+	    this.module_map.put(col_name, c);
+	    
+	    if(c.isPublic()) {
+		// only public collections will appear on the home page
+		// add short description_ to collection_list_
+		Element e = this.doc.createElement(GSXML.COLLECTION_ELEM);
+		e.setAttribute(GSXML.NAME_ATT, col_name);
+		this.collection_list.appendChild(e);
+	    } 
+	    return true;
+	} else {
+	    logger.error("Couldn't configure collection: "+
+			       col_name+".");
+	    return false;
+	}
+    }
+    
+    protected boolean activateSiteByName(String site_name) {
+	logger.info("Activating site: "+site_name+".");
+	
+	// just in case this is a reactivation, deactivate this site first
+	deactivateModule(GSXML.SITE_ELEM, site_name);
+	File configFile = new File(GSFile.siteConfigFile(this.site_home));
+
+	if (!configFile.exists() ) {
+	    logger.error(" site config file: "+configFile.getPath()+" not found!");
+	    return false;
+	}
+	Document config_doc = this.converter.getDOM(configFile);
+	if (config_doc == null) {
+	    logger.error(" couldn't parse site config file: "+configFile.getPath());
+	    return false;
+	}
+	Element config_elem = config_doc.getDocumentElement();
+	
+	Element config_site_list = (Element)GSXML.getChildByTagName(config_elem, GSXML.SITE_ELEM+GSXML.LIST_MODIFIER);
+	if (config_site_list ==null ) {
+	    logger.error("activateSite, no sites found");
+	    return false;
+	}
+	// this is a name to identify the current site in the Communicator 
+	String local_site_name = config_site_list.getAttribute("localSiteName");
+	if (local_site_name.equals("")) {
+	    local_site_name = site_name;
+	}
+
+	Element this_site_elem = GSXML.getNamedElement(config_site_list, GSXML.SITE_ELEM, GSXML.NAME_ATT, site_name);
+	if (this_site_elem == null) {
+	    logger.error("activateSite, site "+site_name+" not found");
+	    return false;
+	}
+	
+	return activateSite(this_site_elem, local_site_name);
+    }
+    
+    protected boolean activateServiceClusterByName(String cluster_name) {
+	return false;
+
+    }
+
+    protected boolean activateServiceRackByName(String module_name) {
+	return false;
+    }
+
+    protected boolean deactivateModule(String type, String name) {
+	
+	if (this.module_map.containsKey(name)) {
+
+	    logger.info(" deactivating "+name);
+	    ModuleInterface m = (ModuleInterface)this.module_map.remove(name);
+	    m.cleanUp(); // clean up any open files/connections etc - can cause trouble on windows
+	    // also remove the xml bit from description list
+	    if (type.equals(GSXML.COLLECTION_ELEM)) {
+		Element this_col = GSXML.getNamedElement(this.collection_list, GSXML.COLLECTION_ELEM, GSXML.NAME_ATT, name);
+		if (this_col != null) {
+		    this.collection_list.removeChild(this_col);
+		}
+		return true;
+	    } else if (type.equals(GSXML.SERVICE_ELEM)) {
+		Element this_service = GSXML.getNamedElement(this.service_list, GSXML.SERVICE_ELEM, GSXML.NAME_ATT, name);
+		if (this_service != null) {
+		    this.service_list.removeChild(this_service);
+		}
+		return true;
+	    } else if (type.equals(GSXML.CLUSTER_ELEM)) {
+		Element this_cluster = GSXML.getNamedElement(this.cluster_list, GSXML.CLUSTER_ELEM, GSXML.NAME_ATT, name);
+		if (this_cluster != null) {
+		    this.cluster_list.removeChild(this_cluster);
+		}
+		return true;
+	    } else if (type.equals(GSXML.SITE_ELEM)) {
+		Element this_site = GSXML.getNamedElement(this.site_list, GSXML.SITE_ELEM, GSXML.NAME_ATT, name);
+		if (this_site != null) {
+		    this.site_list.removeChild(this_site);
+		    
+		    // also remove this sites colls, services, clusters etc
+		    removeRemoteSiteInfo(this.collection_list, GSXML.COLLECTION_ELEM, name);
+		    removeRemoteSiteInfo(this.cluster_list, GSXML.CLUSTER_ELEM, name);
+		    removeRemoteSiteInfo(this.service_list, GSXML.SERVICE_ELEM, name);
+		}
+	    } else {
+		logger.error(" couldn't deactivate coll");
+		// couldn't do it
+		return false;
+	    }
+	}
+	// else not deactivated 
+	return false;
+
+    }
+
+    /**
+     * this looks through a list (module_list) of elements named module_name, 
+     * and removes any whose names start with site_name
+     */
+    protected void removeRemoteSiteInfo(Element module_list, 
+					String module_name, 
+					String site_name) {
+
+	NodeList modules = module_list.getElementsByTagName(module_name);
+	// will this work??
+	for (int i=modules.getLength()-1; i>=0; i--) {
+	    
+	    String name = ((Element)modules.item(i)).getAttribute(GSXML.NAME_ATT);
+	    if (GSPath.getFirstLink(name).equals(site_name)) {
+		module_list.removeChild(modules.item(i));
+	    }
+	}
+    }
+	
+}
+
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/core/ModuleInterface.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/core/ModuleInterface.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/core/ModuleInterface.java	(revision 14125)
@@ -0,0 +1,62 @@
+/*
+ *    ModuleInterface.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.core;
+   
+import org.w3c.dom.Element;                                                
+
+/**
+ * interface for all modules in greenstone.
+ *
+ * all components talk via a process method - in its simplest form,
+ * it takes a String of XML, and returns a String of XML
+ *
+ * the more efficient process method uses DOM Element Nodes instead 
+ * of Strings - this avoids parsing the XML at each module
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @version $Revision$
+ */
+public interface ModuleInterface {
+ 
+  /**
+   * Process an XML request - as a String
+   *
+   * @param xml_in the request to process
+   * @return the response - contains any error messages
+   * @see java.lang.String
+   */
+    abstract public String process(String xml_in);
+
+  /**
+   * Process an XML request - as a DOM model Element
+   *
+   * @param xml_in the request to process
+   * @return the response - contains any error messages
+   * @see org.w3c.dom.Element
+   */
+    abstract public Element process(Element xml_in);
+
+    /** 
+     * Do any clean up necessary for deactivating the module, eg
+     * close any open file handles (gdbm in particular) or windows
+     * holds locks on them.
+     */
+    abstract public void cleanUp();
+}    
+                                                                           
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/core/NZDLReceptionist.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/core/NZDLReceptionist.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/core/NZDLReceptionist.java	(revision 14125)
@@ -0,0 +1,99 @@
+package org.greenstone.gsdl3.core;
+
+import org.greenstone.gsdl3.util.*;
+import org.greenstone.gsdl3.action.*;
+// XML classes
+import org.w3c.dom.Node; 
+import org.w3c.dom.NodeList; 
+import org.w3c.dom.Document; 
+import org.w3c.dom.Element; 
+
+// other java classes
+import java.io.File;
+import java.util.HashMap;
+import java.util.Enumeration;
+
+import org.apache.log4j.*;
+
+/** 
+ * This is a new version of the Receptionist for the NZDL interface
+ * the interface requires a lot more info for each page
+ * @see DefaultReceptionist
+ */
+public class NZDLReceptionist extends DefaultReceptionist {
+
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.core. NZDLReceptionist.class.getName());
+
+    protected void addExtraInfo(Element page) {
+	logger.debug("the  page before adding extra info is");
+	logger.debug(this.converter.getPrettyString(page));
+
+	super.addExtraInfo(page);
+
+	// this gets the collection info
+	Element page_response = (Element)GSXML.getChildByTagName(page, GSXML.PAGE_RESPONSE_ELEM);
+	Element page_request = (Element)GSXML.getChildByTagName(page, GSXML.PAGE_REQUEST_ELEM);
+	Element collection_info = (Element)GSXML.getChildByTagName(page_response, GSXML.COLLECTION_ELEM);
+	if (collection_info== null) {
+	    return;
+	}
+
+	String collection = collection_info.getAttribute("name"); // should we take this from the request instead??
+	// look through services and see if classifier one is present - need to
+	// get the list of classifiers
+	Element service_list = (Element)GSXML.getChildByTagName(collection_info, GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER);
+	if (service_list == null) {
+	    // something weird has gone wrong
+	    return;
+	}
+	
+	Element info_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	String lang = page.getAttribute(GSXML.LANG_ATT);
+	
+	boolean do_classifier = false;
+	boolean do_query = false;
+	Element classifier_service = GSXML.getNamedElement(service_list, GSXML.SERVICE_ELEM, GSXML.NAME_ATT, "ClassifierBrowse");
+	Element query_service = GSXML.getNamedElement(service_list, GSXML.SERVICE_ELEM, GSXML.NAME_ATT, "TextQuery");
+	if (classifier_service != null) {
+	    do_classifier = true;
+	    // find the list of classifiers
+	
+	    String to = GSPath.appendLink(collection, "ClassifierBrowse");
+	    Element info_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, to, lang, ""); 
+	    info_message.appendChild(info_request);
+	}
+	
+	String action = page_request.getAttribute(GSXML.ACTION_ATT);
+	String subaction = page_request.getAttribute(GSXML.SUBACTION_ATT);
+	
+	if (query_service != null && action.equals("p") && subaction.equals("about")) {
+	    do_query = true;
+	    // get the full description
+	    String to = GSPath.appendLink(collection, "TextQuery");
+	    Element query_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, to, lang, "");
+	    info_message.appendChild(query_request);
+	    
+	}
+	
+	Element info_resp_message = (Element) this.mr.process(info_message);
+	Element info_response = (Element) GSXML.getChildByTagName(info_resp_message, GSXML.RESPONSE_ELEM); 
+	//	String path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.SERVICE_ELEM);
+	if (do_classifier) {
+	    Element classifier_service_info = (Element)GSXML.getNamedElement(info_response, GSXML.SERVICE_ELEM, GSXML.NAME_ATT, "CLassifierBrowse");
+	    if (classifier_service_info != null) {
+		service_list.replaceChild(this.doc.importNode(classifier_service_info, true), classifier_service);
+	    }
+	}
+	if (do_query) {
+	    Element query_service_info = (Element)GSXML.getNamedElement(info_response, GSXML.SERVICE_ELEM, GSXML.NAME_ATT, "TextQuery");
+	    if (query_service_info != null) {
+		service_list.replaceChild(this.doc.importNode(query_service_info, true), query_service);
+	    }
+	}
+	logger.debug("the final page before transforming is");
+	logger.debug(this.converter.getPrettyString(page));
+	return;
+    }
+	
+}
+    
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/core/Receptionist.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/core/Receptionist.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/core/Receptionist.java	(revision 14125)
@@ -0,0 +1,281 @@
+package org.greenstone.gsdl3.core;
+
+import org.greenstone.gsdl3.util.*;
+import org.greenstone.gsdl3.action.*;
+// XML classes
+import org.w3c.dom.Node; 
+import org.w3c.dom.NodeList; 
+import org.w3c.dom.Document; 
+import org.w3c.dom.Element; 
+
+// other java classes
+import java.io.File;
+import java.util.HashMap;
+import java.util.Enumeration;
+import java.util.ArrayList;
+
+import org.apache.log4j.*;
+
+/** the most basic Receptionist, used for interface generation. 
+ * Receives requests consisting
+ * of an xml representation of cgi args, and returns the page of data. The requests are processed by the appropriate action class
+ *
+ * @see Action
+ */
+public class Receptionist implements ModuleInterface {
+
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.core.Receptionist.class.getName());
+
+    /** the set up variables */
+    protected HashMap config_params = null;
+    /** container Document to create XML Nodes */
+    protected Document doc=null; 
+   
+    /** a converter class to parse XML and create Docs */
+    protected XMLConverter converter=null;
+
+    /** the message router that the Receptionist and Actions will talk to */
+    protected ModuleInterface mr=null;
+
+    /** the list of actions */
+    protected HashMap action_map=null;
+    
+    /** the list of params */
+    protected GSParams params=null;
+    protected Element language_list = null;
+
+    /** the list of interfaces this is based on */
+    protected ArrayList base_interfaces = null;
+    
+    public Receptionist() {
+	this.converter = new XMLConverter();
+	this.doc = this.converter.newDOM();
+	this.action_map= new HashMap();
+    }
+    
+    public void cleanUp() {}
+    public void setParams(GSParams params) {
+	this.params = params;
+    }
+    public void setConfigParams(HashMap params) {
+	this.config_params = params;
+    }
+    /** sets the message router  - it should already be created and 
+     * configured before  being passed to the receptionist*/
+    public void setMessageRouter(ModuleInterface m) {
+       this.mr = m;
+    }
+
+    /** configures the receptionist */
+    public boolean configure() {
+
+	if (this.config_params==null) {
+	    logger.error(" config variables must be set before calling configure");
+	    return false;
+	}
+	if (this.mr==null) {	   
+	    logger.error(" message router must be set  before calling configure");
+	    return false;
+	}
+
+	// find the config file containing a list of actions
+	File interface_config_file = new File(GSFile.interfaceConfigFile(GSFile.interfaceHome(GlobalProperties.getGSDL3Home(), (String)this.config_params.get(GSConstants.INTERFACE_NAME))));
+	if (!interface_config_file.exists()) {
+	    logger.error(" interface config file: "+interface_config_file.getPath()+" not found!");
+	    return false;
+	}
+	
+	Document config_doc = this.converter.getDOM(interface_config_file);
+	if (config_doc == null) {
+	    logger.error(" could not parse interface config file: "+interface_config_file.getPath());
+	    return false;
+	}
+	Element config_elem = config_doc.getDocumentElement();
+	String base_interface = config_elem.getAttribute("baseInterface");
+	setUpBaseInterface(base_interface);
+	setUpInterfaceOptions(config_elem);
+
+	// load up the actions
+	Element action_list = (Element)GSXML.getChildByTagName(config_elem, GSXML.ACTION_ELEM+GSXML.LIST_MODIFIER);
+	NodeList actions = action_list.getElementsByTagName(GSXML.ACTION_ELEM);
+
+	for (int i=0; i<actions.getLength(); i++) {
+	    Element action = (Element) actions.item(i);
+	    String class_name = action.getAttribute("class");
+	    String action_name = action.getAttribute("name");
+	    Action ac = null;
+	    try {
+		ac = (Action)Class.forName("org.greenstone.gsdl3.action."+class_name).newInstance();
+	    } catch (Exception e) {
+		logger.error(" couldn't load in action "+class_name);
+		e.printStackTrace();
+		continue;
+	    }
+	    ac.setConfigParams(this.config_params);
+	    ac.setMessageRouter(this.mr);
+	    ac.configure();
+	    ac.getActionParameters(this.params);
+	    this.action_map.put(action_name, ac);
+	}
+
+	this.language_list = (Element)GSXML.getChildByTagName(config_elem, "languageList");
+	if (language_list == null) {
+	    logger.error(" didn't find a language list in the config file!!");
+	}
+
+	return true;
+    }
+    /** process using strings - just calls process using Elements */
+    public String process(String xml_in) {
+
+	Element message = this.converter.getDOM(xml_in).getDocumentElement();
+	Element page = process(message);
+	return this.converter.getString(page);
+    }
+
+    /** process - produce a page of data in response to a request 
+     * if something goes wrong, it returns null - 
+     * TODO:  return a suitable message to the user */
+    public Element process(Element message) {
+
+	// get the request out of the message - assume that there is only one
+	Element request = (Element)GSXML.getChildByTagName(message, GSXML.REQUEST_ELEM);
+	if (request == null) {
+	    logger.error(" message had no request!");
+	    return null; 
+	}
+	// check the request type 
+	String type = request.getAttribute(GSXML.TYPE_ATT); // returns "" if no att of this name
+	if (!type.equals(GSXML.REQUEST_TYPE_PAGE)) { 
+	    // now Receptionist forwards non-page requests straight to the MR, and returns the responses
+	    logger.error(" request type is not '"+GSXML.REQUEST_TYPE_PAGE+"', but it is '"+type+"', so forwarding the message to the MR!");
+	    // process the whole message - mr needs <message> tags, and 
+	    // in this case, there may be more than one request in the message
+	    return this.mr.process(message);
+	}	
+	// work out which action to pass to
+	String action = request.getAttribute(GSXML.ACTION_ATT);
+	if (action.equals("")) {
+	    logger.error(" no action specified in the request!");
+	    return null;
+	}
+	
+	// find the  appropriate action	
+	Action a = (Action)this.action_map.get(action);
+	String action_name=null;
+	if (a==null) { // not in the map yet
+	    // try to load a new action
+	    try {
+		action_name = action.substring(0,1).toUpperCase()+action.substring(1)+"Action";
+		Action ac = (Action)Class.forName("org.greenstone.gsdl3.action."+action_name).newInstance();
+		ac.setConfigParams(this.config_params);
+		ac.setMessageRouter(this.mr);
+		ac.configure();
+		ac.getActionParameters(this.params);
+		this.action_map.put(action, ac);
+		a = ac;
+	    } catch (Exception e) {
+		
+		logger.error(" a new action ("+action_name+") was specified and it couldn't be created. Error message:"+e.getMessage());
+		return null;
+	    }
+	}
+
+	// transform the request in some way
+	preProcessRequest(request);
+	// set up the page
+	Element page = this.doc.createElement(GSXML.PAGE_ELEM);
+	page.setAttribute(GSXML.LANG_ATT, request.getAttribute(GSXML.LANG_ATT));
+	
+	// get the page data from the action
+	Element action_response = a.process(message);
+
+	boolean response_only=false;
+	Element param_list = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (param_list != null) {
+	    Element param = GSXML.getNamedElement(param_list, GSXML.PARAM_ELEM, GSXML.NAME_ATT, "ro");
+	    if (param != null) {
+		String value = param.getAttribute("value");
+		if (value.equals("1")) {
+		    response_only = true;
+		}
+	    }
+	}
+	if (response_only) {
+	    // only the response from the action is sent back
+	    return action_response;
+	}
+	
+	// the request is part of the page
+	page.appendChild(GSXML.duplicateWithNewName(this.doc, request, GSXML.PAGE_REQUEST_ELEM, true));
+	// add the response too
+	Element page_response = GSXML.duplicateWithNewName(this.doc, (Element)GSXML.getChildByTagName(action_response, GSXML.RESPONSE_ELEM), GSXML.PAGE_RESPONSE_ELEM, true);
+	page.appendChild(page_response);
+
+	logger.debug(" raw page="+this.converter.getString(page));
+	// transform the result in some way
+	Element resulting_page = postProcessPage(page);
+	return resulting_page;
+	
+    }
+
+    protected boolean setUpBaseInterface(String base_interface) {
+	if (base_interface== null || base_interface.equals("")) {
+	    // there was no base interface, the list remains null
+	    return true;
+	}
+	// foreach base interface
+	while (!base_interface.equals("")) {
+	    // find the base interface config file
+	    File base_interface_config_file = new File(GSFile.interfaceConfigFile(GSFile.interfaceHome(GlobalProperties.getGSDL3Home(), base_interface)));
+	    if (!base_interface_config_file.exists()) {
+		logger.error(" base interface config file: "+base_interface_config_file.getPath()+" not found!");
+		return false;
+	    }
+	    // the interface name is valid, add it to the list
+	    if (base_interfaces == null) {
+		base_interfaces = new ArrayList();
+	    }
+	    base_interfaces.add(base_interface);
+	    // now see if this has a base interface
+	    Document config_doc = this.converter.getDOM(base_interface_config_file);
+	    if (config_doc == null) {
+		logger.error(" could not parse base interface config file: "+base_interface_config_file.getPath());
+		return false;
+	    }
+	    Element config_elem = config_doc.getDocumentElement();
+	    base_interface = config_elem.getAttribute("baseInterface");
+	}
+	return true;
+    }
+
+    protected boolean setUpInterfaceOptions(Element config_elem) {
+	Element option_list = (Element)GSXML.getChildByTagName(config_elem, "optionList");
+	if (option_list != null) {
+	    logger.error("found an option list");
+	    // we set any options in the config params
+	    NodeList options = option_list.getElementsByTagName("option");
+	    for (int i=0; i<options.getLength(); i++) {
+		Element option = (Element)options.item(i);
+		String name = option.getAttribute(GSXML.NAME_ATT);
+		String value = option.getAttribute(GSXML.VALUE_ATT);
+		logger.error("option: "+name+", "+value);
+		if (!name.equals("") && !value.equals("")) {
+		    this.config_params.put(name, value);
+		}
+	    }
+	}
+
+	return true;
+    }
+
+    protected void preProcessRequest(Element request) {
+	return;
+    }
+
+    protected Element postProcessPage(Element page) {
+	return page;
+    }
+    
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/core/TransformingReceptionist.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/core/TransformingReceptionist.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/core/TransformingReceptionist.java	(revision 14125)
@@ -0,0 +1,226 @@
+package org.greenstone.gsdl3.core;
+
+import org.greenstone.gsdl3.util.*;
+import org.greenstone.gsdl3.action.*;
+// XML classes
+import org.w3c.dom.Node; 
+import org.w3c.dom.NodeList; 
+import org.w3c.dom.Document; 
+import org.w3c.dom.Element; 
+
+// other java classes
+import java.io.File;
+import java.util.HashMap;
+import java.util.Enumeration;
+
+import org.apache.log4j.*;
+
+/** A receptionist that uses xslt to transform the page_data before returning it. . Receives requests consisting
+ * of an xml representation of cgi args, and returns the page of data - in 
+ * html by default. The requests are processed by the appropriate action class
+ *
+ * @see Action
+ */
+public class TransformingReceptionist extends Receptionist{
+    
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.core.TransformingReceptionist.class.getName());
+
+    /** the list of xslt to use for actions */
+    protected HashMap xslt_map = null;
+    
+    /** a transformer class to transform xml using xslt */
+    protected XMLTransformer transformer=null;
+
+    public TransformingReceptionist() {
+	super();
+	this.xslt_map = new HashMap();
+	this.transformer = new XMLTransformer();
+    }
+    
+    /** configures the receptionist - overwrite this to set up the xslt map*/
+    public boolean configure() {
+	
+	if (this.config_params==null) {
+	    logger.error(" config variables must be set before calling configure");
+	    return false;
+	}
+	if (this.mr==null) {	   
+	    logger.error(" message router must be set  before calling configure");
+	    return false;
+	}
+	
+	// find the config file containing a list of actions
+	File interface_config_file = new File(GSFile.interfaceConfigFile(GSFile.interfaceHome(GlobalProperties.getGSDL3Home(), (String)this.config_params.get(GSConstants.INTERFACE_NAME))));
+	if (!interface_config_file.exists()) {
+	    logger.error(" interface config file: "+interface_config_file.getPath()+" not found!");
+	    return false;
+	}
+	Document config_doc = this.converter.getDOM(interface_config_file, "utf-8");
+	if (config_doc == null) {
+	    logger.error(" could not parse interface config file: "+interface_config_file.getPath());
+	    return false;
+	}
+	Element config_elem = config_doc.getDocumentElement();
+	String base_interface = config_elem.getAttribute("baseInterface");
+	setUpBaseInterface(base_interface);
+	setUpInterfaceOptions(config_elem);
+
+	Element action_list = (Element)GSXML.getChildByTagName(config_elem, GSXML.ACTION_ELEM+GSXML.LIST_MODIFIER);
+	NodeList actions = action_list.getElementsByTagName(GSXML.ACTION_ELEM);
+
+	for (int i=0; i<actions.getLength(); i++) {
+	    Element action = (Element) actions.item(i);
+	    String class_name = action.getAttribute("class");
+	    String action_name = action.getAttribute("name");
+	    Action ac = null;
+	    try {
+		ac = (Action)Class.forName("org.greenstone.gsdl3.action."+class_name).newInstance();
+	    } catch (Exception e) {
+		logger.error(" couldn't load in action "+class_name);
+		e.printStackTrace();
+		continue;
+	    }
+	    ac.setConfigParams(this.config_params);
+	    ac.setMessageRouter(this.mr);
+	    ac.configure();
+	    ac.getActionParameters(this.params);
+	    this.action_map.put(action_name, ac);
+
+	    // now do the xslt map
+	    String xslt = action.getAttribute("xslt");
+	    if (!xslt.equals("")) {
+		this.xslt_map.put(action_name, xslt);
+	    }
+	    NodeList subactions = action.getElementsByTagName(GSXML.SUBACTION_ELEM);
+	    for (int j=0; j<subactions.getLength(); j++) {
+		Element subaction = (Element)subactions.item(j);
+		String subname = subaction.getAttribute(GSXML.NAME_ATT);
+		String subxslt = subaction.getAttribute("xslt");
+		
+		String map_key = action_name+":"+subname;
+		logger.debug("adding in to xslt map, "+map_key+"->"+subxslt);
+		this.xslt_map.put(map_key, subxslt);
+	    }
+	    
+	   
+	}
+	Element lang_list = (Element)GSXML.getChildByTagName(config_elem, "languageList");
+	if (lang_list == null) {
+	    logger.error(" didn't find a language list in the config file!!");
+	} else {
+	    this.language_list = (Element) this.doc.importNode(lang_list, true);
+	}
+
+	return true;
+    }
+
+
+    protected Element postProcessPage(Element page) {
+	
+	// might need to add some data to the page
+	addExtraInfo(page);
+	// transform the page using xslt
+	Element transformed_page = transformPage(page);
+	
+	return transformed_page;
+    }
+    
+    /** overwrite this to add any extra info that might be needed in the page before transformation */
+    protected void addExtraInfo(Element page) {}
+
+    /** transform the page using xslt
+     * we need to get any format element out of the page and add it to the xslt
+     * before transforming */
+    protected Element transformPage(Element page) {
+
+	logger.debug("page before transfomring:");
+	logger.debug(this.converter.getPrettyString(page));
+
+	Element request = (Element)GSXML.getChildByTagName(page, GSXML.PAGE_REQUEST_ELEM);
+	String action = request.getAttribute(GSXML.ACTION_ATT);
+	String subaction = request.getAttribute(GSXML.SUBACTION_ATT);
+	
+	String output = request.getAttribute(GSXML.OUTPUT_ATT);
+	// we should choose how to transform the data based on output, eg diff
+	// choice for html, and wml??
+	// for now, if output=xml, we don't transform the page, we just return 
+	// the page xml
+	if (output.equals("xml")) {
+	    return page;
+	}
+
+	Element cgi_param_list = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	String collection = "";
+	if (cgi_param_list != null) {
+	    HashMap params = GSXML.extractParams(cgi_param_list, false);
+	    collection = (String)params.get(GSParams.COLLECTION);
+	    if (collection == null) collection = "";
+	}
+	
+	String xslt_file = getXSLTFileName(action, subaction, collection);
+	if (xslt_file==null) {
+	    // cant transform the page - return null or the original?
+	    logger.error(" cant find the xslt file needed, so returning the original page!");
+	    return page;
+	}
+	Document style_doc = this.converter.getDOM(new File(xslt_file), "UTF-8");
+	if (style_doc == null) {
+	    logger.error(" cant parse the xslt file needed, so returning the original page!");
+	    return page;
+	    
+	}
+
+	// look for the format element in the page response
+	Element page_response = (Element)GSXML.getChildByTagName(page, GSXML.PAGE_RESPONSE_ELEM);
+	Element format_elem = (Element)GSXML.getChildByTagName(page_response, GSXML.FORMAT_ELEM);
+	if (format_elem != null) {
+	    //page_response.removeChild(format_elem);
+	    logger.debug("format elem="+this.converter.getPrettyString(format_elem));
+	    // need to transform the format info
+	    String stylesheet_file = GSFile.stylesheetFile(GlobalProperties.getGSDL3Home(), (String)this.config_params.get(GSConstants.SITE_NAME), collection, (String)this.config_params.get(GSConstants.INTERFACE_NAME), base_interfaces,   "config_format.xsl");
+	    Document stylesheet_doc = this.converter.getDOM(new File(stylesheet_file));
+	    if (stylesheet_doc != null) {
+		Document format_doc = this.converter.newDOM();
+		format_doc.appendChild(format_doc.importNode(format_elem, true));
+		Element new_format = (Element)this.transformer.transform(stylesheet_doc, format_doc);
+	    logger.debug("new format elem="+this.converter.getPrettyString(new_format));
+	    
+	    // add it in to the main stylesheet
+		GSXSLT.mergeStylesheets(style_doc, new_format);
+	    } else {
+		logger.error(" couldn't parse the config_format stylesheet, adding the format info as is");
+		GSXSLT.mergeStylesheets(style_doc, format_elem);
+	    }
+	    logger.debug("the converted stylesheet is:");
+	    logger.debug(this.converter.getPrettyString(style_doc.getDocumentElement()));
+	}
+	
+	// there is a thing called a URIResolver which you can set for a transformer or transformer factory. may be able to use this instead of this absoluteIncludepaths hack
+	GSXSLT.absoluteIncludePaths(style_doc, GlobalProperties.getGSDL3Home(), (String)this.config_params.get(GSConstants.SITE_NAME), collection, (String)this.config_params.get(GSConstants.INTERFACE_NAME), base_interfaces);
+	// put the page into a document - this is necessary for xslt to get the paths right if you have paths relative to the document root eg /page.
+	Document doc = this.converter.newDOM();
+	doc.appendChild(doc.importNode(page, true));
+	return (Element)this.transformer.transform(style_doc, doc, config_params);          
+    }
+
+    protected String getXSLTFileName(String action, String subaction,
+				     String collection) {
+
+	String name = null;
+	if (!subaction.equals("")) {
+	    String key = action+":"+subaction;
+	    name = (String) this.xslt_map.get(key);
+	}
+	// try the action by itself
+	if (name==null) {
+	    name = (String) this.xslt_map.get(action);
+	}
+	// now find the absolute path
+	String stylesheet = GSFile.stylesheetFile(GlobalProperties.getGSDL3Home(), (String)this.config_params.get(GSConstants.SITE_NAME), collection, (String)this.config_params.get(GSConstants.INTERFACE_NAME), base_interfaces, name);
+	if (stylesheet==null) {
+	    logger.info(" cant find stylesheet for "+name);
+	}
+	return stylesheet;
+    }
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/DocumentStream.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/DocumentStream.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/DocumentStream.java	(revision 14125)
@@ -0,0 +1,55 @@
+/*
+ *    DocumentStream.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.selfContained;
+
+// XML classes
+import org.w3c.dom.Document; 
+
+// other java classes
+import java.io.Serializable;
+
+
+/**
+ * Document Stream represents a stream of XML documents
+ *
+ * Based on algorithms in ...
+ *
+ * @author <a href="http://www.cs.waikato.ac.nz/~say1/">stuart yeates</a> (<a href="mailto:s.yeates@cs.waikato.ac.nz">s
+.yeates@cs.waikato.ac.nz</a>) at the <a href="http://www.nzdl.org">New Zealand Digital Library</a>
+ * @version $Revision$
+ * 
+ */
+public interface DocumentStream extends Cloneable, Serializable {
+  
+  /**
+   * Get the next document
+   * 
+   * @exception java.io.Exception when something goes wrong
+   * @return the next document
+   */
+  public Document nextDocument() throws Exception ;
+  /**
+   * Is there a next document?
+   * 
+   * @exception java.io.Exception when something goes wrong
+   * @return true if there is a next document
+   */
+  public boolean hasNextDocument() throws Exception ;
+  
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/FilesDocumentStream.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/FilesDocumentStream.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/FilesDocumentStream.java	(revision 14125)
@@ -0,0 +1,196 @@
+/*
+ *    DocumentStreamFromFiles.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.selfContained;
+
+// XML classes
+import org.w3c.dom.Document; 
+import org.xml.sax.InputSource;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import org.apache.xerces.dom.DocumentImpl;
+import org.apache.xerces.dom.ElementImpl;
+import org.apache.xerces.dom.TextImpl;
+import org.w3c.dom.Document; 
+
+// other java classes
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Vector;
+
+
+  
+/**
+ * DocumentStreamFromFiles creates a stream of documents from a directory or directories.
+ *
+ * @author <a href="http://www.cs.waikato.ac.nz/~say1/">stuart yeates</a> (<a href="mailto:s.yeates@cs.waikato.ac.nz">s
+.yeates@cs.waikato.ac.nz</a>) at the <a href="http://www.nzdl.org">New Zealand Digital Library</a>
+ * @version $Revision$
+ * @see java.io.File
+ * @see DocumentStream
+ */
+public class FilesDocumentStream 
+  implements DocumentStream {
+  /** the files we've found so far */
+  Vector files = new Vector();
+  /** the directories we've found so far */
+  Vector directories = new Vector();
+
+  /**
+   * Filename constructor
+   * 
+   * @exception java.io.IOException file access do
+   * @param filename the filename of the file or directory
+   */
+  public FilesDocumentStream(String filename)  {
+    File file = new File(filename);
+    if (file.exists() && file.isDirectory())
+      directories.add(file.getAbsolutePath());
+    else
+      files.add(file.getAbsolutePath());
+  }
+  /**
+   * File constructor
+   * 
+   * @exception java.io.IOException file access do
+   * @param file a handle to the file
+   */
+  public FilesDocumentStream(File file) {
+    if (file.exists() && file.isDirectory())
+      directories.add(file.getAbsolutePath());
+    else
+      files.add(file.getAbsolutePath());
+  }
+
+  /** 
+   * A small inner class to filter out those files that don't 
+   * end in ".xml" or ".XML"
+   */
+  class XMLFilenameFilter implements FilenameFilter {
+    /** Tests if a specified file should be included in a file list. */
+    public boolean accept(File dir, String name) {
+      String target = ".xml";
+      if (name.length() < target.length())
+	return false;
+      String extension = name.substring(name.length() - 4, name.length());
+      //System.out.println(name + " ==>> " +  extension);
+      if (extension.equalsIgnoreCase(target)) {
+	return true;
+      } else {
+	return false;
+      }
+    }    
+  }
+
+  /**
+   * Opens a new directory if there are no files are queued
+   * 
+   * @exception java.io.IOException when the underlying file access does
+   */
+  protected void expandIfNecessary() {
+    while (directories.size() > 0) {
+      String dirname = (String) directories.elementAt(0);
+      directories.removeElement(dirname);
+      File dir = new File(dirname);
+      if (!dir.exists()) throw new Error ("error in expand: expecting a directory " + dirname);
+      String[] fileArray = dir.list();
+      for (int i=0;i<fileArray.length;i++){
+	File file = new File(dir, fileArray[i]);
+	if (file.exists() && file.isDirectory()) 
+	  directories.add(file.getPath());
+      }
+      
+      fileArray = dir.list(new XMLFilenameFilter());
+      for (int i=0;i<fileArray.length;i++){
+	File file = new File(dir, fileArray[i]);
+	if (file.exists() && !file.isDirectory())
+	  files.add(file.getPath());
+      }
+      if (files.size() > 0)
+	return;
+    }
+  }
+  
+  /**
+   * Returns the next document
+   * 
+   * @exception java.io.IOException when the underlying file access does
+   * @return the next document
+   */
+  public Document nextDocument()
+    throws Exception {
+    
+    if (!hasNextDocument()) throw new Error("Doesn't have another Document");
+
+    String filename = (String) files.elementAt(files.size() - 1);
+    files.removeElementAt(files.size() - 1);
+    File file = new File(filename);
+    
+    Reader reader = new FileReader(file);
+    InputSource xml_source = new InputSource(reader);
+
+    XMLUtil.getDOMParser().parse(xml_source);
+    Document doc = XMLUtil.getDOMParser().getDocument();
+    
+    return doc;
+  }
+    
+  /**
+   * Is there another document ?
+   * 
+   * @exception java.io.IOException when the underlying file access does
+   * @return the next document
+   */
+
+  public boolean hasNextDocument()  throws Exception {
+    expandIfNecessary();
+    return (files.size() > 0);
+  }
+  /**
+   * Tests...
+   *
+   * 
+   * @exception java.io.IOException when ...
+   * @param args the arguments ...
+   */
+
+  public static void main(String args[]) throws Exception
+  {
+   
+    StreamResult result = new StreamResult(System.out);
+    TransformerFactory transformerFactory = TransformerFactory.newInstance();
+    
+    FilesDocumentStream stream = new FilesDocumentStream(".");
+    while (stream.hasNextDocument()) {
+      Document document = stream.nextDocument();
+      Transformer transformer = transformerFactory.newTransformer();
+      Source source = new DOMSource(document);
+      transformer.transform(source,result);
+      System.out.println();
+      System.out.println();
+    }
+
+  } 
+}
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/GeneratedDocumentStream.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/GeneratedDocumentStream.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/GeneratedDocumentStream.java	(revision 14125)
@@ -0,0 +1,148 @@
+/*
+ *    GenerateDocumentStream.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.selfContained;
+
+// XML classes
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import org.apache.xerces.dom.DocumentImpl;
+import org.apache.xerces.dom.ElementImpl;
+import org.apache.xerces.dom.TextImpl;
+import org.w3c.dom.Document; 
+
+
+// other java classes
+
+/**
+ * GeneratedDocumentStream generates an unbounded stream of XML documents
+ * Each containing a single string.
+ *
+ * Based as a wrapper around an Increment object
+ *
+ * @author <a href="http://www.cs.waikato.ac.nz/~say1/">stuart yeates</a> (<a href="mailto:s.yeates@cs.waikato.ac.nz">s
+.yeates@cs.waikato.ac.nz</a>) at the <a href="http://www.nzdl.org">New Zealand Digital Library</a>
+ * @version $Revision$
+ * @see DocumentStream
+ * @see Increment
+ * 
+ */
+public class GeneratedDocumentStream implements DocumentStream {
+  
+  /** The next string */
+  protected String next = "";
+  /** The underlying Increment object */
+  protected Increment incrementer = new IncrementRange();
+
+  /** The default constructor. Generates ASCII-only documents */
+  public GeneratedDocumentStream() {
+
+  }
+  
+  /** 
+   * Custom constructor 
+   *
+   * @param incrementer the incrementer to use (controls the character set to use)
+   */
+  public GeneratedDocumentStream(Increment incrementer) {
+    this.incrementer = incrementer;
+  }
+  
+  /** 
+   * Custom constructor 
+   *
+   * @param next the string for the first document (must suit the incrementor)
+   */
+  public GeneratedDocumentStream(String next) {
+    this.next = next;
+  }
+  
+  /** 
+   * Custom constructor 
+   *
+   * @param incrementer the incrementer to use (controls the character set to use)
+   * @param next the string for the first document (must suit the incrementor)
+   */
+  public GeneratedDocumentStream(Increment incrementer, String next) {
+    this.incrementer = incrementer;
+    this.next = next;
+  }
+  /** 
+   * Custom constructor 
+   *
+   * @param first the first letter in the alphabet
+   * @param last the last letter in the alphabet
+   */
+  public GeneratedDocumentStream(char first, char last) {
+    this.incrementer = new IncrementRange(first,last);
+  }
+
+
+  /**
+   * Generates the nest document in the sequence
+   * 
+   * @exception java.io.Exception when something goes wrong in the XML stuff
+   * @return the next Document
+   * @see org.w3c.dom.Document
+   */
+  public Document nextDocument() {
+
+
+   DocumentImpl doc = new DocumentImpl(true);
+    
+   ElementImpl root = new ElementImpl(doc,"document");
+   TextImpl text = new TextImpl(doc,next);
+    
+   doc.appendChild(root);
+   root.appendChild(text);
+ 
+   next = incrementer.incrementString(next);
+   return doc;
+   
+  }
+  /**
+   * Are there more documents ?
+   * 
+   * @return yes
+   */
+  public boolean hasNextDocument(){
+    return true;
+  }
+  /**
+   * Generates an unbounded stream of documents
+   */
+  public static void main(String args[]) throws Exception
+  {
+    
+    StreamResult result = new StreamResult(System.out);
+    TransformerFactory transformerFactory = TransformerFactory.newInstance();
+    
+    GeneratedDocumentStream stream = new GeneratedDocumentStream();
+    while (stream.hasNextDocument()) {
+      Document document = stream.nextDocument();
+      Transformer transformer = transformerFactory.newTransformer();
+      Source source = new DOMSource(document);
+      transformer.transform(source,result);
+    }
+  }
+  
+}
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/Increment.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/Increment.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/Increment.java	(revision 14125)
@@ -0,0 +1,111 @@
+/*
+ *    Increment.java
+ *    Copyright (C) 2000-2001 Stuart Yeates 
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 package we're in
+package org.greenstone.gsdl3.selfContained;
+
+// java standard library classes used
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Serializable;
+import java.io.Writer;
+
+
+/**
+ * Class Increment is an abstract class for incrementing streams and strings
+ *
+ *
+ * @author <a href="http://www.cs.waikato.ac.nz/~say1/">stuart yeates</a> (<a href="mailto:s.yeates@cs.waikato.ac.nz">s.yeates@cs.waikato.ac.nz</a>) at the <a href="http://www.nzdl.org">New Zealand Digital Library</a>
+ * @version $Revision$
+ */
+
+abstract public class Increment implements Cloneable, Serializable
+{
+  /**
+   * Increment a string of characters
+   * 
+   * @exception java.io.Exception if any of the characters in the string are outside the range of first-last
+   * @param str the string to be incremented
+   * @return the incremented string
+   * @see Increment
+   */
+  abstract String incrementString(String str);
+
+  /**
+   * Increment a stream of characters, reading from the reader and writing the incremented characters to the writer
+   * 
+   * @exception java.io.Exception if any of the characters in the string are outside the range of first-last
+   * @param str the string to be incremented
+   * @return the incremented string
+   * @see Increment
+   */
+  abstract long incrementStream(Reader rdr, Writer wtr);
+
+  /**
+   * Print to standard out a verbose message about the 
+   * results of incrementing this string
+   * 
+   * @param s the string to increment
+   * @see #incrementString(String)
+   */
+  final void checkStr(String s) {
+    try {
+      System.out.println("incrementing: \"" + s +
+			 "\" to \"" + incrementString(s) +
+			 "\"  " + stringToOctal(s) +
+			 " ===> " + stringToHex(incrementString(s)));
+    } catch (Exception e) {
+      System.out.println("Caught exception: " + e);
+    }
+  }
+
+  /**
+   * Converts a unicode string to Hex
+   * 
+   * @exception java.io.IOException when ...
+   * @param s the string to convert
+   * @return a string in hex
+   * @see Integer#toHexString(int)
+   */
+  static final String stringToHex(String s) {
+    StringBuffer buffer = new StringBuffer();
+    for (int i=0;i<s.length();i++) {
+      buffer.append(" 0x");
+      buffer.append(Integer.toHexString(s.charAt(i)));
+    } 
+    return buffer.toString();
+  }
+
+  /**
+   * Converts a unicode string to Octal
+   * 
+   * @param s the string
+   * @return the string in octal
+   * @see Integer#toOctalString(int)
+   */
+  static final String stringToOctal(String s) {
+    StringBuffer buffer = new StringBuffer();
+    for (int i=0;i<s.length();i++) {
+      buffer.append(" 0x");
+      buffer.append(Integer.toOctalString(s.charAt(i)));
+    } 
+    return buffer.toString();
+  }
+}
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/IncrementRange.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/IncrementRange.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/IncrementRange.java	(revision 14125)
@@ -0,0 +1,240 @@
+/*
+ *    IncrementRange.java
+ *    Copyright (C) 2000-2001 Stuart Yeates 
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 package we're in
+package org.greenstone.gsdl3.selfContained;
+
+// java standard library classes used
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Serializable;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+
+/**
+ * Class IncrementRange increments strings and streams over a limited range of Characters.
+ *
+ *
+ * @author <a href="http://www.cs.waikato.ac.nz/~say1/">stuart yeates</a> (<a href="mailto:s.yeates@cs.waikato.ac.nz">s.yeates@cs.waikato.ac.nz</a>) at the <a href="http://www.nzdl.org">New Zealand Digital Library</a>
+ * @version $Revision$
+ * @see Increment
+ * 
+ */
+final public class IncrementRange
+  extends Increment 
+  implements Cloneable, Serializable
+{
+  /**
+   * Create an IncrementRange which counts between first and last inclusive
+   * 
+   * @param first the first character in the range
+   * @param last the last character in the range
+   * @see Increment
+   */
+  IncrementRange(char first, char last){
+    this.first = first;
+    this.last = last;
+  }
+  /**
+   * Create a default IncrementRange
+   * 
+   * @see Increment
+   */
+  IncrementRange(){
+  }
+
+  /**
+   * Create a IncrementRange over all Unicode characters
+   * 
+   * @see Increment
+   */
+  IncrementRange(boolean b){
+    if (true) {
+      this.first = Character.MIN_VALUE;
+      this.last = Character.MAX_VALUE;
+    }
+  }  
+  /** the last character in out range */
+  private char first = ' ';
+  /** the last character in out range */
+  private char last = 'z';
+
+  /**
+   * Increment a stream of characters, reading from the reader and writing the incremented characters to the writer
+   * 
+   * @exception java.io.Error if any of the characters in the string are outside the range of first-last
+   * @param str the string to be incremented
+   * @return the incremented string
+   * @see Increment
+   */
+  long incrementStream(Reader rdr, Writer wtr) {
+    try {
+      long count = 0; // the return value
+    
+      int i = rdr.read();
+      boolean carry = true;
+    
+      while (i != -1) {
+	char c = (char) i;
+      
+	// check the validity of the character we're about to increment
+	if (c < first || c > last) 
+	  throw new Error("Character '" + c + "' is ouside range");
+      
+	if (c == last) {
+	  if (carry == true) {
+	    wtr.write(first);
+	    carry = true;
+	  } else {
+	    wtr.write(c);
+	    carry = false;
+	  }
+	} else {
+	  if (carry == true) {
+	    wtr.write(++c);
+	    carry = false;
+	  } else {
+	    wtr.write(c);
+	    carry = false;
+	  } 
+	}
+	count++;
+
+	// read the next character
+	i = rdr.read();
+      }
+      if (carry == true) {
+	wtr.write(first);
+	count++;
+      }
+      return count;
+    } catch (IOException e) {
+      System.err.println("IOException in incrementStream()");
+      throw new Error(e.toString());
+    }
+  }
+
+  /**
+   * Increment a string of characters
+   * 
+   * @exception java.lang.Error if any of the characters in the string are outside the range of first-last
+   * @param str the string to be incremented
+   * @return the incremented string
+   * @see Increment
+   */
+  public final String incrementString(String str)  {
+    StringBuffer buffer = new StringBuffer();
+    if (str.equals("")) {
+      buffer.append(first);
+      return buffer.toString();
+    } else {
+      boolean carry = true;
+      for (int i=0;i<str.length();i++) {
+	char c = str.charAt(i);
+	if (c < first || c > last) 
+	  throw new Error("Character '" + c + "' is ouside range");
+
+	if (c == last) {
+	  if (carry == true) {
+	    buffer.append(first);
+	    carry = true;
+	  } else {
+	    buffer.append(c);
+	    carry = false;
+	  }
+	} else {
+	  if (carry == true) {
+	    buffer.append(++c);
+	    carry = false;
+	  } else {
+	    buffer.append(c);
+	    carry = false;
+	  } 
+	}
+      }
+      if (carry == true)
+	buffer.append(first);
+    }
+    return buffer.toString();
+  }
+
+
+  /**
+   * Test the incrementing of strings (never returns)
+   */
+  public static void testStringIncrement() throws IOException
+  {
+    IncrementRange n = new IncrementRange ();
+    try {
+      String tmp = "";
+      System.out.println(stringToHex(tmp));
+      while (true) {
+	//checkStr(tmp);
+	tmp = n.incrementString(tmp);
+	n.checkStr(tmp);
+      }
+    } catch (Exception e) {
+      System.out.println("Caught exception: " + e);
+    }
+
+  }
+
+  /**
+   * Test the incrementing of streams (never returns)
+   *
+   */
+  public static void testStreamIncrement() 
+  {
+    IncrementRange n = new IncrementRange ();
+    try {
+      long counter = 0;
+      String tmp = "";
+      System.out.println(stringToHex(tmp));
+      while (true) {
+	//checkStr(tmp);
+	String tmp2 = n.incrementString(tmp);
+	StringWriter wtr = new StringWriter();
+	n.incrementStream(new StringReader(tmp),wtr);
+	if (!tmp2.equals(wtr.toString()))
+	  throw new Exception("Error: \"" + tmp2 + 
+			      "\" and \"" + tmp2 + 
+			      "\"");
+	counter++;
+	if (counter % 1000000 == 0)
+	  System.out.println(counter + " " + tmp);
+
+	tmp = tmp2;
+      }
+    } catch (Exception e) {
+      System.out.println("Caught exception: " + e);
+    }
+  }
+
+  /**
+   * Tests stream incrementing 
+   *
+   * 
+   */
+  public static void main(String args[]) 
+  {
+    testStreamIncrement();
+  } 
+}
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/QueryDocumentStream.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/QueryDocumentStream.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/QueryDocumentStream.java	(revision 14125)
@@ -0,0 +1,281 @@
+/*
+ *    QueryDocumentStream.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.selfContained;
+
+// XML classes
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import org.w3c.dom.Document;
+
+// other java classes
+import java.io.StringReader;
+
+/**
+ * QueryDocumentStream takes another document stream and removes 
+ * from the stream all documents which fail to match a XSLT query.
+ * The default query returns only those documents containing the 
+ * string "the".
+ *
+ * @author <a href="http://www.cs.waikato.ac.nz/~say1/">stuart yeates</a> (<a href="mailto:s.yeates@cs.waikato.ac.nz">s
+.yeates@cs.waikato.ac.nz</a>) at the <a href="http://www.nzdl.org">New Zealand Digital Library</a>
+ * @version $Revision$
+ * @see DocumentStream
+ * 
+ */
+public class QueryDocumentStream implements DocumentStream {
+  
+  /** The default XSLT query string. Is true (returns a non-empty document) when the input document contains the string "the". */
+  public static final String DEFAULT_QUERY_STRING =   
+    "<xsl:stylesheet version=\"1.0\" " +
+    "                    xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">" +
+    "   <xsl:output omit-xml-declaration=\"yes\"/>" +
+    
+    "   <xsl:template match=\"/*\">" +
+    "      <xsl:if test=\"contains(.,'the')\">" +
+    "         <xsl:copy-of select=\".\"/>" +
+    "      </xsl:if>" + 
+    "   </xsl:template>" +
+    "</xsl:stylesheet>";
+  /** The first part of the default quesy for a string other than "the" */
+  public static final String DEFAULT_QUERY_STRING_1_1 =   
+    "<xsl:stylesheet version=\"1.0\" " +
+    "                    xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">" +
+    "   <xsl:output omit-xml-declaration=\"yes\"/>" +
+    
+    "   <xsl:template match=\"/*\">" +
+    "      <xsl:if test=\"contains(.,'";
+
+  /** The second part of the default quesy for a string other than "the" */
+  public static final String DEFAULT_QUERY_STRING_1_2 =   
+    "')\">" +
+    "         <xsl:copy-of select=\".\"/>" +
+    "      </xsl:if>" + 
+    "   </xsl:template>" +
+    "</xsl:stylesheet>";
+
+
+  /** The query */
+  protected StreamSource query = new StreamSource(new StringReader(DEFAULT_QUERY_STRING));
+
+  /** The underlying DocumentStream object */
+  protected DocumentStream stream = null;
+
+  /** A cached Document */
+  protected Document cached = null;
+
+  /** The transformer factory */
+  TransformerFactory transformerFactory  = null;
+
+  /** The transformer */
+  Transformer transformer  = null;
+
+  /** Uses the default query (looking for the) over the default DocumentStream (all ascii strings) */
+  public QueryDocumentStream() {
+    this.query = new StreamSource(new StringReader(DEFAULT_QUERY_STRING));
+    this.stream = new GeneratedDocumentStream();
+
+    try {
+      this.transformerFactory 
+	= org.apache.xalan.processor.TransformerFactoryImpl.newInstance();
+      
+      this.transformer
+	= transformerFactory.newTransformer(query);
+    } catch (TransformerConfigurationException e) {
+      System.err.println("XMLTransformer: couldn't create transformer object: "+e.getMessage());
+    }
+  }
+  
+  /** Looks for the given string in the stream of documents  */
+  public QueryDocumentStream(DocumentStream stream, String query) {
+    String fullQuery = DEFAULT_QUERY_STRING_1_1 + query + DEFAULT_QUERY_STRING_1_2;
+    this.query = new StreamSource(new StringReader(fullQuery));
+    this.stream = stream;
+
+    try {
+      this.transformerFactory 
+	= org.apache.xalan.processor.TransformerFactoryImpl.newInstance();
+      
+      this.transformer
+	= transformerFactory.newTransformer(this.query);
+    } catch (TransformerConfigurationException e) {
+      System.err.println("XMLTransformer: couldn't create transformer object: "+e.getMessage());
+    }
+  }
+  
+
+  /** Applies the stylesheet to the stream.  */
+  public QueryDocumentStream(DocumentStream stream, StreamSource source) {
+    this.query = source;
+    this.stream = stream;
+
+    try {
+      this.transformerFactory 
+	= org.apache.xalan.processor.TransformerFactoryImpl.newInstance();
+      
+      this.transformer
+	= transformerFactory.newTransformer(query);
+    } catch (TransformerConfigurationException e) {
+      System.err.println("XMLTransformer: couldn't create transformer object: "+e.getMessage());
+    }
+  }
+  
+
+  /** The default constructor. Searches for documents containing "the" */
+  public QueryDocumentStream(DocumentStream stream) {
+    this.query = new StreamSource(new StringReader(DEFAULT_QUERY_STRING));
+    this.stream = stream;
+
+    try {
+      this.transformerFactory 
+	= org.apache.xalan.processor.TransformerFactoryImpl.newInstance();
+      
+      this.transformer
+	= transformerFactory.newTransformer(query);
+    } catch (TransformerConfigurationException e) {
+      System.err.println("XMLTransformer: couldn't create transformer object: "+e.getMessage());
+    }
+  }
+  /**
+   * Generates the nest document in the sequence
+   * 
+   * @exception java.io.Exception when something goes wrong in the XML stuff
+   * @return the next Document
+   * @see org.w3c.dom.Document
+   */
+  public Document nextDocument() throws Exception {
+
+    if (hasNextDocument() == false)
+      throw new Error("no more docs");
+    Document result = cached;
+    cached = null;
+    return result;
+  }
+  /**
+   * Are there more documents ?
+   * 
+   * @return true if there are more docs
+   */
+  public boolean hasNextDocument() throws Exception {
+    lookInStream();
+    return (cached != null);
+  }
+  /**
+   *
+   * 
+   * @exception java.io.IOException when ...
+   * @param arg2 ... 
+   * @param arg1 ...
+   * @return ...
+   */
+  protected boolean lookInStream() throws Exception {
+
+    while (stream.hasNextDocument() && cached == null) {
+      
+      Document candidate = stream.nextDocument();
+      
+      DOMSource input = new DOMSource(candidate);
+      DOMResult output = new DOMResult();
+      
+      try {
+	
+	transformer.transform(input, output);
+      
+	// if the transformed document is not empty don't cache it
+	if (output.getNode().getFirstChild() != null)
+	  cached = (Document) output.getNode();
+      
+      } catch (TransformerConfigurationException e) {
+	System.err.println("XMLTransformer: couldn't create transformer object: "+e.getMessage());
+      } catch (TransformerException e) {
+	System.err.println("XMLTransformer: couldn't transform the source: " + e.getMessage());
+	cached = null;
+	return false;
+      } catch (Exception e) {
+	System.err.println("Exception: " + e.getMessage());
+	cached = null;
+	return false;
+      }
+      
+      if (false) { // debugging info
+	
+	try {
+	  StreamResult result = new StreamResult(System.out);
+	  Transformer transformer = transformerFactory.newTransformer();
+	  
+	  Source source = new DOMSource(candidate);
+	  transformer.transform(source,result);
+	  
+	  System.out.print(" ==> ");
+	  
+	  if (cached != null) {
+	    Source source2 = new DOMSource(cached);
+	    transformer.transform(source2,result);
+	  } 
+	  System.out.println();
+	  System.out.println("======================================================");
+	  
+	} catch (TransformerConfigurationException e) {
+	  System.err.println("XMLTransformer: couldn't create transformer object: "+e.getMessage());
+	} catch (TransformerException e) {
+	  System.err.println("XMLTransformer: couldn't transform the source: " + e.getMessage());
+	  cached = null;
+	  return false;
+	} catch (Exception e) {
+	  System.err.println("Exception: " + e.getMessage());
+	  cached = null;
+	  return false;
+	}
+	
+      }
+    }
+    return cached == null;    
+  }
+
+  /**
+   * Generates an unbounded stream of documents
+   */
+  public static void main(String args[]) throws Exception
+  {
+    TransformerFactory transformerFactory = TransformerFactory.newInstance();
+    Transformer transformer = transformerFactory.newTransformer();
+    
+    GeneratedDocumentStream gStream = new GeneratedDocumentStream();
+    QueryDocumentStream qStream = new QueryDocumentStream(gStream);
+    while (qStream.hasNextDocument()) {
+      Document document = qStream.nextDocument();
+      
+      StreamResult result = new StreamResult(System.out);
+      
+      Source source = new DOMSource(document);
+      transformer.transform(source,result);
+      
+      System.out.println();
+      System.out.println("======================================================");
+    }
+  }
+  
+}
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/XMLUtil.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/XMLUtil.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/XMLUtil.java	(revision 14125)
@@ -0,0 +1,96 @@
+/*
+ *    XMLUtil.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.selfContained;
+
+// XML classes
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import org.apache.xerces.parsers.DOMParser;
+
+// other java classes
+import java.io.IOException;
+
+
+/**
+ * Class XMLUtil holds static global XML configuration objects. 
+ * 
+ * @author <a href="http://www.cs.waikato.ac.nz/~say1/">stuart yeates</a> (<a href="mailto:s.yeates@cs.waikato.ac.nz">s
+.yeates@cs.waikato.ac.nz</a>) at the <a href="http://www.nzdl.org">New Zealand Digital Library</a>
+ * @version $Revision$
+ * 
+ */
+class XMLUtil {
+
+  /** the singleton instance */
+  protected static XMLUtil instance = null;
+
+
+  /** JAXP parser factory */ 
+  protected DocumentBuilderFactory doc_build_fact=null;
+
+  /** JAXP parser factory */ 
+  static public DocumentBuilderFactory getDocumentBuilderFactory() {
+    if (instance == null) 
+      init();
+    return instance.doc_build_fact;
+  }
+
+  /** JAXP parser */ 
+  protected DocumentBuilder doc_builder=null;
+
+  /** JAXP parser */ 
+  static public DocumentBuilder getDocumentBuilder() {
+    if (instance == null) 
+      init();
+    return instance.doc_builder;
+   }
+
+  /** xerces parser */
+  protected DOMParser parser = null;
+
+  /** xerces parser */
+  static public DOMParser getDOMParser() {
+    if (instance == null) 
+      init();
+    return instance.parser;
+  }
+
+  /** initalise the statics */
+  static protected void init() {
+    instance = new XMLUtil();
+    try {
+      instance.doc_build_fact = DocumentBuilderFactory.newInstance();
+      
+      instance.doc_builder = instance.doc_build_fact.newDocumentBuilder(); 
+      instance.parser = new DOMParser();
+    } catch (Exception e) {
+      System.out.println("XMLConverter:exception "+e.getMessage());
+    }
+  }
+
+  /**
+   * Checks that the objects can be instantiated
+   *
+   */
+  public static void main(String args[]) throws IOException
+  {
+    XMLUtil.getDOMParser();
+  }
+}
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/go.dtd
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/go.dtd	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/selfContained/go.dtd	(revision 14125)
@@ -0,0 +1,103 @@
+<!-- P is the Paragraph of HTML -->
+<!ELEMENT P (#PCDATA)>
+
+<!-- Each Go file consists of one or several GoGame -->
+<!ELEMENT Go (GoGame*)>
+
+<!-- Each GoGame consists of the game Information and the game tree -->
+
+<!ELEMENT GoGame (Information,Nodes)>
+<!ATTLIST GoGame name CDATA #IMPLIED>
+<!ELEMENT Nodes (((Node|Black|White),(Node|Variation|Black|White|Comment)*)?)>
+
+<!ELEMENT Information (Application?|BoardSize?|BlackPlayer?|BlackRank?|
+	WhitePlayer?|WhiteRank?|Date?|Time?|Komi?|Result?|Handicap?|User?|
+	Copyright?|Annotation?|BlackTeam?|WhiteTeam?|Round?|Rules?|Source?)*>
+<!ELEMENT Application (#PCDATA)>
+<!ATTLIST Application format CDATA #IMPLIED>
+<!ELEMENT BoardSize (#PCDATA)>
+<!ATTLIST BoardSize format CDATA #IMPLIED>
+<!ELEMENT BlackPlayer (#PCDATA)>
+<!ATTLIST BlackPlayer format CDATA #IMPLIED>
+<!ELEMENT WhitePlayer (#PCDATA)>
+<!ATTLIST WhitePlayer format CDATA #IMPLIED>
+<!ELEMENT BlackRank (#PCDATA)>
+<!ATTLIST BlackRank format CDATA #IMPLIED>
+<!ELEMENT WhiteRank (#PCDATA)>
+<!ATTLIST WhiteRank format CDATA #IMPLIED>
+<!ELEMENT Date (#PCDATA)>
+<!ATTLIST Date format CDATA #IMPLIED>
+<!ELEMENT Time (#PCDATA)>
+<!ATTLIST Time format CDATA #IMPLIED>
+<!ELEMENT Komi (#PCDATA)>
+<!ATTLIST Komi format CDATA #IMPLIED>
+<!ELEMENT Handicap (#PCDATA)>
+<!ATTLIST Handicap format CDATA #IMPLIED>
+<!ELEMENT Result (#PCDATA)>
+<!ATTLIST Result format CDATA #IMPLIED>
+<!ELEMENT User (#PCDATA)>
+<!ELEMENT Copyright (P+)>
+<!ELEMENT Annotation (#PCDATA)>
+<!ELEMENT BlackTeam (#PCDATA)>
+<!ELEMENT WhiteTeam (#PCDATA)>
+<!ELEMENT Round (#PCDATA)>
+<!ELEMENT Rules (#PCDATA)>
+<!ATTLIST Rules format CDATA #IMPLIED>
+<!ELEMENT Source (#PCDATA)>
+<!ATTLIST Source format CDATA #IMPLIED>
+
+<!-- Game representation in Nodes -->
+
+<!ELEMENT Node ((SGF|Comment|Black|White|AddBlack|AddWhite|Mark|Delete)*)>
+<!ATTLIST Node name CDATA #IMPLIED>
+
+<!-- Possible content of a node (unordered) -->
+
+<!-- Alternative form of specifying the position as tag content. -->
+<!-- The board position is either like D10 or 4,10 (for larger boards). -->
+<!ELEMENT at (#PCDATA)>
+
+<!ELEMENT Comment (P+)>
+<!ELEMENT Black ((at)*)>
+<!ATTLIST Black
+	at CDATA #IMPLIED
+	number CDATA #IMPLIED
+	timeleft CDATA #IMPLIED
+	annotate CDATA #IMPLIED>
+<!ELEMENT White ((at)*)>
+<!ATTLIST White
+	at CDATA #IMPLIED
+	number CDATA #IMPLIED
+	timeleft CDATA #IMPLIED
+	annotate CDATA #IMPLIED>
+<!ELEMENT AddBlack ((at)*)>
+<!ATTLIST AddBlack
+	at CDATA #IMPLIED>
+<!ELEMENT AddWhite ((at)*)>
+<!ATTLIST AddWhite
+	at CDATA #IMPLIED>
+<!ELEMENT Delete ((at)*)>
+<!ATTLIST Delete
+	at CDATA #IMPLIED>
+<!ELEMENT Mark ((at)*)>
+<!ATTLIST Mark 
+	label CDATA #IMPLIED
+	at CDATA #IMPLIED
+	type (square|circle|triangle) #IMPLIED
+	territory (black|white) #IMPLIED>
+<!ELEMENT BlackToPlay (#PCDATA)>
+<!ELEMENT WhiteToPlay (#PCDATA)>
+<!ELEMENT Line (#PCDATA)>
+<!ATTLIST Line 
+	format CDATA #IMPLIED
+	type CDATA #IMPLIED>
+
+<!-- This is to take care of SGF tags, which are not translated -->
+<!ELEMENT SGF (Arg*)>
+<!ATTLIST SGF
+	type CDATA #REQUIRED>
+<!ELEMENT Arg (#PCDATA)>
+
+<!-- Note that the Variation are ALTERNATIVES to the current node -->
+<!-- This is different from SGF and makes the file easier to read by humans -->
+<!ELEMENT Variation ((Node|Variation|White|Black|Comment)*)>
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/AbstractBrowse.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/AbstractBrowse.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/AbstractBrowse.java	(revision 14125)
@@ -0,0 +1,753 @@
+/*
+ *    AbstractBrowse.java
+ *    Copyright (C) 2005 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.service;
+
+
+// Greenstone classes
+import org.greenstone.gsdl3.util.GSXML;
+import org.greenstone.gsdl3.util.GSPath;
+import org.greenstone.gsdl3.util.MacroResolver;
+import org.greenstone.gsdl3.util.OID;
+
+// XML classes
+import org.w3c.dom.Document;
+import org.w3c.dom.Element; 
+import org.w3c.dom.NodeList;
+
+// General Java classes
+import java.util.ArrayList;
+
+import org.apache.log4j.*;
+
+/** Partially implements a generic classifier service
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ */
+public abstract class AbstractBrowse
+    extends ServiceRack {
+
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.AbstractBrowse.class.getName());
+
+    // the browsing services
+    private static final String CLASSIFIER_SERVICE = "ClassifierBrowse";
+    private static final String CLASSIFIER_METADATA_SERVICE = "ClassifierBrowseMetadataRetrieve";
+
+    // do we want to keep info request?
+    
+    protected static final String STRUCT_PARAM = "structure";
+    protected static final String INFO_PARAM = "info";
+    
+    protected static final String STRUCT_ANCESTORS = "ancestors";
+    protected static final String STRUCT_PARENT = "parent";
+    protected static final String STRUCT_SIBS = "siblings";
+    protected static final String STRUCT_CHILDREN = "children";
+    protected static final String STRUCT_DESCENDS = "descendants";
+    protected static final String STRUCT_ENTIRE = "entire";
+
+    protected static final String INFO_NUM_SIBS = "numSiblings";
+    protected static final String INFO_NUM_CHILDREN = "numChildren";
+    protected static final String INFO_SIB_POS = "siblingPosition";
+
+    protected Element config_info = null; // the xml from the config file
+
+    protected MacroResolver macro_resolver = null;
+
+    protected String default_document_type = null;
+    /** constructor */
+    protected AbstractBrowse()
+    {
+    }
+
+
+    /** configure this service */
+    public boolean configure(Element info, Element extra_info)
+    {
+	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+
+	logger.info("Configuring AbstractBrowse...");
+  	this.config_info = info;
+      	if (macro_resolver != null) {
+	    macro_resolver.setSiteDetails(this.site_http_address, this.cluster_name);
+	    // set up the macro resolver
+	    Element replacement_elem = (Element)GSXML.getChildByTagName(extra_info, "replaceList");
+	    if (replacement_elem != null) {
+		macro_resolver.addMacros(replacement_elem);
+	    }
+
+	}
+
+ 
+        // check that there are classifiers specified
+        Element class_list = (Element)GSXML.getChildByTagName(info, GSXML.CLASSIFIER_ELEM+GSXML.LIST_MODIFIER);
+        if (class_list == null) {
+            // no classifiers specified
+            return false;
+        }
+	
+	// get the display and format elements from the coll config file for
+	// the classifiers
+	extractExtraClassifierInfo(info, extra_info);
+	
+        // short_service_info_ - the browse one
+        Element cb_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+        cb_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_BROWSE);
+        cb_service.setAttribute(GSXML.NAME_ATT, CLASSIFIER_SERVICE);
+        this.short_service_info.appendChild(cb_service);
+	
+	// metadata retrieval for the browsing  
+        Element cbmr_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+        cbmr_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
+        cbmr_service.setAttribute(GSXML.NAME_ATT, CLASSIFIER_METADATA_SERVICE);
+        this.short_service_info.appendChild(cbmr_service);
+
+	// the format info
+	Element cb_format_info = this.doc.createElement(GSXML.FORMAT_ELEM);
+	boolean format_found = false;
+
+	// try the default format first
+	Element def_format = (Element) GSXML.getChildByTagName(info, GSXML.FORMAT_ELEM);
+	if (def_format != null) {
+	    cb_format_info.appendChild(GSXML.duplicateWithNewName(this.doc, def_format, GSXML.DEFAULT_ELEM, true));
+	    format_found = true;
+	}
+	
+	// add in to the description a simplified list of classifiers
+        NodeList classifiers = class_list.getElementsByTagName(GSXML.CLASSIFIER_ELEM);
+	for(int i=0; i<classifiers.getLength(); i++) {
+	    Element cl = (Element)classifiers.item(i);
+	    Element new_cl = (Element)this.doc.importNode(cl, false); // just import this node, not the children
+	    
+	    // get the format info out, and put inside a classifier element
+	    Element format_cl = (Element)new_cl.cloneNode(false);
+	    Element format = (Element)GSXML.getChildByTagName(cl, GSXML.FORMAT_ELEM);
+	    if (format != null) {
+		
+		//copy all the children
+		NodeList elems = format.getChildNodes();
+		for (int j=0; j<elems.getLength();j++) {
+		    format_cl.appendChild(this.doc.importNode(elems.item(j), true));
+		}
+		cb_format_info.appendChild(format_cl);
+		format_found = true;
+	    }
+	    	    
+	}
+	    
+	if (format_found) {
+	    this.format_info_map.put(CLASSIFIER_SERVICE, cb_format_info);
+	}
+
+	// look for document display format - is there a default doc type??
+	String path = GSPath.appendLink(GSXML.DISPLAY_ELEM, GSXML.FORMAT_ELEM);
+	Element display_format = (Element)GSXML.getNodeByPath(extra_info, path);
+	if (display_format != null) {
+	    // check for docType option.
+	    Element doc_type_opt = GSXML.getNamedElement(display_format, "gsf:option", GSXML.NAME_ATT, "documentType");
+	    if (doc_type_opt != null) {
+		String value = doc_type_opt.getAttribute(GSXML.VALUE_ATT);
+		if (!value.equals("")) {
+		    this.default_document_type = value;
+		}
+	    }
+	}
+
+	return true;
+    }
+
+    protected Element getServiceDescription(String service_id, String lang, String subset) {
+
+	if (service_id.equals(CLASSIFIER_SERVICE)) {
+	    
+	    Element class_list = (Element)GSXML.getChildByTagName(this.config_info, GSXML.CLASSIFIER_ELEM+GSXML.LIST_MODIFIER);
+	    if (class_list == null) {
+            // no classifiers specified
+		return null;
+	    }
+	    
+	    Element cb_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    cb_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_BROWSE);
+	    cb_service.setAttribute(GSXML.NAME_ATT, CLASSIFIER_SERVICE);
+	    cb_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_NAME,  getTextString(CLASSIFIER_SERVICE+".name", lang)));
+	    cb_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_DESCRIPTION,  getTextString(CLASSIFIER_SERVICE+".description", lang)));
+	    
+	    Element cl_list = this.doc.createElement(GSXML.CLASSIFIER_ELEM+GSXML.LIST_MODIFIER);
+	    cb_service.appendChild(cl_list);
+	    NodeList classifiers = class_list.getElementsByTagName(GSXML.CLASSIFIER_ELEM);
+	    for(int i=0; i<classifiers.getLength(); i++) {
+		Element cl = (Element)classifiers.item(i);
+		Element new_cl = (Element)this.doc.importNode(cl, false); // just import this node, not the children
+			
+        	//String content = cl.getAttribute(GSXML.CLASSIFIER_CONTENT_ATT);
+		
+		//get the classify title  from the database
+	         String class_id =  cl.getAttribute(GSXML.NAME_ATT);
+		 String content = getMetadata(class_id,"Title"); 
+
+                cl_list.appendChild(new_cl);
+		String text = GSXML.getDisplayText(cl, 
+						   GSXML.DISPLAY_TEXT_NAME, 
+						   lang, "en");
+		if (text == null || text.equals("")) {
+		    // no display element was specified, use the metadata name
+		    // for now this looks in the class properties file
+		    // this needs to use a general metadata thing instead
+		    text = getMetadataNameText(content+".buttonname", lang);
+		}
+		if (text == null) {
+		    text = content;
+		}
+		
+		
+		Element cl_name = GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_NAME, text);
+		new_cl.appendChild(cl_name);
+
+		// description
+		
+		String meta_name = getMetadataNameText(content, lang);
+		if (meta_name==null) {
+		    meta_name = content;
+		}
+		String [] array = {meta_name};
+		String description = getTextString("ClassifierBrowse.classifier_help", lang, array);
+		Element cl_desc = GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_DESCRIPTION, description);
+		new_cl.appendChild(cl_desc);
+		
+	    }
+	    return cb_service;
+	}
+	
+	// these ones are probably never called, but put them here just in case
+	
+	if (service_id.equals(CLASSIFIER_METADATA_SERVICE)) {
+	    
+	    Element cbmr_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    cbmr_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
+	    cbmr_service.setAttribute(GSXML.NAME_ATT, CLASSIFIER_METADATA_SERVICE);
+	    return cbmr_service;
+	}
+
+	return null;
+    }
+
+    /** this looks for any classifier specific display or format info from extra_info and adds it in to the correct place in info */
+    protected boolean extractExtraClassifierInfo(Element info, Element extra_info) {
+	
+	if (extra_info == null) {
+	    return false;
+	}
+	
+	Document owner = info.getOwnerDocument();
+	// so far we have display and format elements that we need for classifiers
+	NodeList classifiers = info.getElementsByTagName(GSXML.CLASSIFIER_ELEM);
+	Element config_browse = (Element)GSXML.getChildByTagName(extra_info, GSXML.BROWSE_ELEM);
+
+	for (int i=0; i<classifiers.getLength();i++) {
+	    Element cl = (Element)classifiers.item(i);
+	    String name = cl.getAttribute(GSXML.NAME_ATT);
+
+	    //Element node_extra = GSXML.getNamedElement(config_browse,
+	    //					       GSXML.CLASSIFIER_ELEM,
+	    //					       GSXML.NAME_ATT,
+	    //					       name);
+            //now use the position to get the node - CL1 
+            int position = Integer.parseInt(name.substring(2));
+	    Element node_extra = null;
+            NodeList cls = config_browse.getElementsByTagName(GSXML.CLASSIFIER_ELEM);
+            if (position >0 && position <= cls.getLength()) {
+	        node_extra  = (Element) cls.item((position -1)); 
+	    }
+
+	    if (node_extra == null) {
+		logger.error("GS2REtrieve: haven't found extra info for classifier named "+name);
+		continue;
+	    }
+	    
+	    // get the display elements if any - displayName
+	    NodeList display_names = node_extra.getElementsByTagName(GSXML.DISPLAY_TEXT_ELEM);
+	    if (display_names !=null) {
+		Element display = owner.createElement(GSXML.DISPLAY_ELEM);
+		for (int j=0; j<display_names.getLength(); j++) {
+		    Element e = (Element)display_names.item(j);
+		    cl.appendChild(owner.importNode(e, true));
+		    
+		}
+	    }
+	    
+	    // get the format element if any 
+	    Element format = (Element)GSXML.getChildByTagName(node_extra, GSXML.FORMAT_ELEM);
+	    if (format==null) { // try a generic one that applies to all classifiers
+		format = (Element)GSXML.getChildByTagName(extra_info,
+							  GSXML.FORMAT_ELEM);
+	    }
+	    if (format!=null) { // append to index info
+		cl.appendChild(owner.importNode(format, true));
+	    }
+	} // for each classifier
+
+	// now check for default format info
+	Element default_format = (Element)GSXML.getChildByTagName(config_browse, GSXML.FORMAT_ELEM);
+	if (default_format!=null) { // append to  info
+	    info.appendChild(owner.importNode(default_format, true));
+	}
+
+	return true;
+    }
+	    
+    protected Element processClassifierBrowse(Element request) {
+	
+	// Create a new (empty) result message
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.setAttribute(GSXML.FROM_ATT, CLASSIFIER_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+	
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	Element query_node_list = (Element) GSXML.getChildByTagName(request, GSXML.CLASS_NODE_ELEM+GSXML.LIST_MODIFIER);
+	if (query_node_list == null) {
+	    logger.error(" ClassifierBrowse request specified no doc nodes.\n");
+	    return result;
+	}
+
+	// Get the parameters of the request
+	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (param_list == null) {
+	    logger.error(" ClassifierBrowse request had no paramList.");
+	    return result;  // Return the empty result
+	}
+	
+	// the type of info required
+	boolean want_structure = false;
+	boolean want_info = false;
+
+	ArrayList info_types=new ArrayList();
+	// The document structure information desired
+	boolean want_ancestors = false;
+	boolean want_parent = false;
+	boolean want_siblings = false;
+	boolean want_children = false;
+	boolean want_descendants = false;
+
+	boolean want_entire_structure = false;
+	// Process the request parameters
+	NodeList params = param_list.getElementsByTagName(GSXML.PARAM_ELEM);
+	for (int i=0; i<params.getLength();i++) {
+	    
+	    Element param = (Element)params.item(i);
+	    String p_name = param.getAttribute(GSXML.NAME_ATT);
+	    String p_value = GSXML.getValue(param);
+	    // Identify the structure information desired
+	    if (p_name.equals(STRUCT_PARAM)) {
+		want_structure = true;
+		
+		// This is NOT locale sensitive
+		if (p_value.equals(STRUCT_ANCESTORS))
+		    want_ancestors = true;
+		else if (p_value.equals(STRUCT_PARENT))
+		    want_parent = true;
+		else if (p_value.equals(STRUCT_SIBS))
+		    want_siblings = true;
+		else if (p_value.equals(STRUCT_CHILDREN))
+		    want_children = true;
+		else if (p_value.equals(STRUCT_DESCENDS))
+		    want_descendants = true;
+		else if (p_value.equals(STRUCT_ENTIRE))
+		    want_entire_structure = true;
+		else
+		    logger.error("AbstractDocumentRetrieve Warning: Unknown value \"" + p_value + "\".");
+	    } else if (p_name.equals(INFO_PARAM)) {
+		want_info = true;
+		info_types.add(p_value);
+	    }
+	}
+
+	// Make sure there is no repeated information
+	if (want_ancestors)
+	    want_parent = false;
+	if (want_descendants)
+	    want_children = false;
+	
+	// the node list to hold the results
+	Element node_list = this.doc.createElement(GSXML.CLASS_NODE_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(node_list);
+	
+	// Get the nodes
+	String[] node_ids = GSXML.getAttributeValuesFromList(query_node_list, 
+							     GSXML.NODE_ID_ATT);
+	for (int i = 0; i < node_ids.length; i++) {
+	    // Add the document to the list
+	    Element node = this.doc.createElement(GSXML.CLASS_NODE_ELEM);
+	    node_list.appendChild(node);
+
+	    String node_id = node_ids[i];
+	    node.setAttribute(GSXML.NODE_ID_ATT, node_id);
+	    
+	    if (idNeedsTranslating(node_id)) {
+		node_id = translateId(node_id);
+		if (node_id == null) {
+		    continue;
+		}
+		node.setAttribute(GSXML.NODE_ID_ATT, node_id);
+	    }
+	    
+	    if (want_info) {
+
+		Element node_info_elem = this.doc.createElement("nodeStructureInfo");
+		node.appendChild(node_info_elem);
+		
+		for (int j=0; j<info_types.size(); j++) {
+		    String info_type = (String)info_types.get(j);
+		    String info_value = getStructureInfo(node_id, info_type);
+		    if (info_value != null) {
+			Element info_elem = this.doc.createElement("info");
+			info_elem.setAttribute(GSXML.NAME_ATT, info_type);
+			info_elem.setAttribute(GSXML.VALUE_ATT, info_value);
+			node_info_elem.appendChild(info_elem);
+		    }
+		}
+	    }
+	    
+	    if (want_structure) {
+		// all structure info goes into a nodeStructure elem
+		Element structure_elem = this.doc.createElement(GSXML.NODE_STRUCTURE_ELEM);
+		node.appendChild(structure_elem);
+		
+		if (want_entire_structure) {
+		    String root_id = getRootId(node_id);
+		    Element root_node = createClassifierNode(root_id); //, true, false);
+		    addDescendants(root_node, root_id, true);
+		    structure_elem.appendChild(root_node);
+		    continue; // with the next document, we dont need to do any more here
+		}
+		
+		// Add the requested structure information
+		Element base_node = createClassifierNode(node_id); //, false, false);
+		
+		//Ancestors: continually add parent nodes until the root is reached
+		Element top_node = base_node; // the top node so far
+		if (want_ancestors) {
+		    String current_id = node_id;
+		    while (true) {
+			String parent_id = getParentId(current_id);
+			//Element parent = getParent(current_id);
+			if (parent_id == null)
+			    break; // no parent
+			Element parent_node = createClassifierNode(parent_id);
+			parent_node.appendChild(top_node);
+			current_id = parent_id;//.getAttribute(GSXML.NODE_ID_ATT);
+			top_node = parent_node;
+		    }
+		}
+		// Parent: get the parent of the selected node
+		else if (want_parent) {
+		    String parent_id = getParentId(node_id);
+		    if (parent_id != null) {
+			Element parent_node = createClassifierNode(parent_id);
+			parent_node.appendChild(base_node);
+			top_node = parent_node;
+		    }
+		}
+		
+		// now the top node is the root of the structure
+		structure_elem.appendChild(top_node);
+		
+		//Siblings: get the other descendants of the selected node's parent
+		if (want_siblings) {
+		    
+		    Element parent_node = (Element)base_node.getParentNode(); // this may be the structure element if there has been no request for parents or ancestors
+		    String parent_id = getParentId(node_id);
+		    // add siblings, - returns a pointer to the new current node 
+		    base_node = addSiblings(parent_node, parent_id, node_id);
+		}
+		
+		// Children: get the descendants, but only one level deep
+		if (want_children) {
+		    addDescendants(base_node, node_id, false);
+		} 
+		// Descendants: recursively get every descendant 
+		else if (want_descendants) {
+		    addDescendants(base_node, node_id, true);
+		}
+	    } // if want structure
+	} // for each doc
+	return result;
+    }
+
+
+    protected Element processClassifierBrowseMetadataRetrieve(Element request) {
+
+	// Create a new (empty) result message
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	result.setAttribute(GSXML.FROM_ATT, CLASSIFIER_METADATA_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+
+	// Get the parameters of the request
+	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (param_list == null) {
+	    logger.error("AbstractBrowse, ClassifierBrowseMetadataRetrieve Error: missing paramList.\n");
+	    return result;  // Return the empty result
+	}
+
+	// The metadata information required
+	ArrayList metadata_names_list = new ArrayList();
+	boolean all_metadata = false;
+	// Process the request parameters
+	Element param = (Element) param_list.getFirstChild();
+	while (param != null) {
+	    // Identify the metadata information desired
+	    if (param.getAttribute(GSXML.NAME_ATT).equals("metadata")) {
+		String metadata = GSXML.getValue(param);
+		if (metadata.equals("all")) {
+		    all_metadata = true;
+		    break;
+		}
+		metadata_names_list.add(metadata);
+	    } 
+	    param = (Element) param.getNextSibling();
+	}
+	
+	Element node_list = this.doc.createElement(GSXML.CLASS_NODE_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(node_list);
+	
+	// Get the nodes
+	Element request_node_list = (Element) GSXML.getChildByTagName(request, GSXML.CLASS_NODE_ELEM+GSXML.LIST_MODIFIER);
+	if (request_node_list == null) {
+	    logger.error(" ClassifierBrowseMetadataRetrieve request had no "+GSXML.CLASS_NODE_ELEM+GSXML.LIST_MODIFIER);
+ 	    return result;
+ 	}
+	
+	NodeList request_nodes = request_node_list.getChildNodes();
+	for (int i = 0; i < request_nodes.getLength(); i++) {
+	    Element request_node = (Element) request_nodes.item(i);
+	    String node_id = request_node.getAttribute(GSXML.NODE_ID_ATT);
+	    
+	    // Add the document to the results list
+	    Element new_node = (Element)this.doc.importNode(request_node, false);
+	    node_list.appendChild(new_node);
+
+	    if (idNeedsTranslating(node_id)) {
+		node_id = translateId(node_id);
+	    }
+	    if (node_id == null) {
+		continue;
+	    }
+	    
+	    Element metadata_list = getMetadataList(node_id, all_metadata, metadata_names_list);
+	    new_node.appendChild(metadata_list);
+	}
+	
+	return result;
+    }
+
+
+    /** Creates a classifier node */
+    protected Element createClassifierNode(String node_id)
+    {
+	Element node = this.doc.createElement(GSXML.CLASS_NODE_ELEM);
+	node.setAttribute(GSXML.NODE_ID_ATT, node_id);
+	return node;
+    }
+
+    /** create an element to go into the structure. A node element
+     * has the form
+     * <docNode nodeId='xxx' nodeType='leaf' docType='hierarchy'/>
+     */
+    protected Element createDocNode(String node_id) {
+	Element node = this.doc.createElement(GSXML.DOC_NODE_ELEM);
+	node.setAttribute(GSXML.NODE_ID_ATT, node_id);
+
+	String doc_type = null;
+	if (default_document_type != null) {
+	    doc_type = default_document_type;
+	} else {
+	    doc_type = getDocType(node_id);
+	}
+	node.setAttribute(GSXML.DOC_TYPE_ATT, doc_type);
+	String node_type = getNodeType(node_id, doc_type);	
+	node.setAttribute(GSXML.NODE_TYPE_ATT, node_type);
+	return node;
+    }
+
+   /** returns the node type of the specified node.
+	should be one of 
+	GSXML.NODE_TYPE_LEAF, 
+	GSXML.NODE_TYPE_INTERNAL, 
+	GSXML.NODE_TYPE_ROOT
+    */
+    protected String getNodeType(String node_id, String doc_type) {
+	if (doc_type.equals(GSXML.DOC_TYPE_SIMPLE)) {
+	    return GSXML.NODE_TYPE_LEAF;
+	}
+
+	if (getParentId(node_id)==null) {
+	    return GSXML.NODE_TYPE_ROOT;
+	}
+	if (doc_type.equals(GSXML.DOC_TYPE_PAGED)) {
+	     return GSXML.NODE_TYPE_LEAF;
+	}
+	if (getChildrenIds(node_id)==null) {
+	    return GSXML.NODE_TYPE_LEAF;
+	}
+	return GSXML.NODE_TYPE_INTERNAL;	
+	
+    }
+
+    /** adds all the children of doc_id the the doc element,
+     * and if recursive=true, adds all their children as well*/
+    protected void addDescendants(Element node, String node_id, 
+				  boolean recursive)
+    {
+	ArrayList child_ids = getChildrenIds(node_id);
+	if (child_ids==null) return;
+	for (int i=0; i< child_ids.size(); i++) {
+	    String child_id = (String)child_ids.get(i);
+	    Element child_elem;
+	    if (isDocumentId(child_id)) {
+		child_elem = createDocNode(child_id);
+	    } else {
+		child_elem = createClassifierNode(child_id);
+	    }
+	    node.appendChild(child_elem);
+	    if (recursive) {
+		addDescendants(child_elem, child_id, recursive);
+	    }
+	}
+    }
+
+    /** adds all the siblings of current_id to the parent element. 
+      returns the new current element*/
+    protected Element addSiblings(Element parent_node, String parent_id, 
+				  String current_id) {
+	Element current_node = (Element)parent_node.getFirstChild();
+	if (current_node == null) {
+	    // create a sensible error message
+	    logger.error(" there should be a first child.");
+	    return null;
+	}
+	// remove the current child,- will add it in later in its correct place
+	parent_node.removeChild(current_node);
+
+	// add in all the siblings,
+	addDescendants(parent_node, parent_id, false);
+
+	// find the node that is now the current node
+	// this assumes that the new node that was created is the same as 
+	// the old one that was removed - we may want to replace the new one 
+	// with the old one.
+	Element new_current = GSXML.getNamedElement(parent_node, current_node.getNodeName(), GSXML.NODE_ID_ATT, current_id);
+	return new_current;
+    }
+
+    /** returns true if oid ends in
+	.fc (firstchild), 
+	.lc (lastchild), 
+	.pr (parent), 
+	.ns (next sibling), 
+	.ps (prev sibling), 
+	.rt (root) 
+	.ss (specified sibling), 
+	false otherwise 
+    */
+    protected boolean idNeedsTranslating(String node_id) {
+	return OID.needsTranslating(node_id);
+    }
+
+    /** returns the list of sibling ids, including the specified node_id */
+    protected ArrayList getSiblingIds(String node_id) {
+	String parent_id = getParentId(node_id);
+	if (parent_id == null) {
+	    return null;
+	}
+	return getChildrenIds(parent_id);
+
+    }
+
+    /** if id ends in .fc, .pc etc, then translate it to the correct id */
+    abstract protected String translateId(String node_id);
+
+    /** returns the document type of the doc that the specified node 
+	belongs to. should be one of 
+	GSXML.DOC_TYPE_SIMPLE, 
+	GSXML.DOC_TYPE_PAGED, 
+	GSXML.DOC_TYPE_HIERARCHY
+    */
+    abstract protected String getDocType(String node_id);
+
+    /** returns the id of the root node of the document containing node node_id. . may be the same as node_id */
+    abstract protected String getRootId(String node_id);
+    /** returns a list of the child ids in order, null if no children */
+    abstract protected ArrayList getChildrenIds(String node_id);
+    /** returns the node id of the parent node, null if no parent */
+    abstract protected String getParentId(String node_id);
+ 
+    /** returns true if the id refers to a document (rather than 
+     * a classifier node)
+     */
+    abstract protected boolean isDocumentId(String node_id);
+
+    /** get the metadata for the classifier node node_id
+     * returns a metadataList element:
+     * <metadataList><metadata name="xxx">value</metadata></metadataList>
+     * if all_metadata is true, returns all available metadata, otherwise just
+     * returns requested metadata
+     */
+    abstract protected Element getMetadataList(String node_id,
+					       boolean all_metadata,
+					       ArrayList metadata_names);
+
+    /** get the particular metadata (identified by the metadata name) for the classifier node node_id
+     * 
+     */
+    abstract protected String getMetadata(String node_id, String metadata_name);
+
+
+    /** returns the structural information asked for.
+     * info_type may be one of
+     * INFO_NUM_SIBS, INFO_NUM_CHILDREN, INFO_SIB_POS
+     */
+    abstract protected String getStructureInfo(String node_id, String info_type);    
+//      /** needs to get info from gdbm database - if the calling code gets it already it may pay to pass it in instead */
+//     protected String resolveTextMacros(String doc_content, String doc_id, String lang)
+//     {
+// 	DBInfo info = null;
+// 	if (doc_content.indexOf("_httpdocimg_")!=-1) {
+// 	    String top_doc_id = OID.getTop(doc_id);
+// 	    info = this.gdbm_src.getInfo(top_doc_id);
+// 	    if (info == null) {
+// 		// perhaps we had per.iods in the ids - just try the current id
+// 		top_doc_id = doc_id;
+// 		info = this.gdbm_src.getInfo(top_doc_id);
+// 	    }
+// 	    if (info != null) {
+// 		String archivedir = info.getInfo("archivedir");
+// 		String image_dir  = this.site_http_address + "/collect/"+this.cluster_name+"/index/assoc/"+archivedir;
+		
+// 		// Resolve all "_httpdocimg_"s
+// 		doc_content = doc_content.replaceAll("_httpdocimg_", image_dir);
+// 	    }
+// 	}
+// 	// resolve any collection specific macros
+// 	doc_content = macro_resolver.resolve(doc_content, lang, GS2MacroResolver.SCOPE_TEXT, doc_id, info);
+// 	return doc_content;
+//     }
+
+   
+}   
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/AbstractDocumentRetrieve.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/AbstractDocumentRetrieve.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/AbstractDocumentRetrieve.java	(revision 14125)
@@ -0,0 +1,704 @@
+/*
+ *    AbstractDocumentRetrieve.java
+ *    a base class for retrieval services
+
+ *    Copyright (C) 2005 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.service;
+
+// Greenstone classes
+//import org.greenstone.gdbm.*;
+import org.greenstone.gsdl3.core.GSException;
+import org.greenstone.gsdl3.util.GSXML;
+import org.greenstone.gsdl3.util.GSPath;
+import org.greenstone.gsdl3.util.MacroResolver;
+import org.greenstone.gsdl3.util.OID;
+
+// XML classes
+import org.w3c.dom.Document;
+import org.w3c.dom.Element; 
+import org.w3c.dom.NodeList;
+
+// General Java classes
+import java.io.File;
+import java.util.StringTokenizer;
+import java.util.Set;
+import java.util.Iterator;
+import java.util.ArrayList;
+
+
+import org.apache.log4j.*;
+
+/** Abstract class for Document Retrieval Services
+ *
+ * @author <a href="mailto:greenstone@cs.waikato.ac.nz">Katherine Don</a>
+ */
+
+public abstract class AbstractDocumentRetrieve
+    extends ServiceRack {
+
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.AbstractDocumentRetrieve.class.getName());
+
+    // the services on offer
+    protected static final String DOCUMENT_STRUCTURE_RETRIEVE_SERVICE = "DocumentStructureRetrieve";
+    protected static final String DOCUMENT_METADATA_RETRIEVE_SERVICE = "DocumentMetadataRetrieve";
+    protected static final String DOCUMENT_CONTENT_RETRIEVE_SERVICE = "DocumentContentRetrieve";
+    
+    protected static final String STRUCT_PARAM = "structure";
+    protected static final String INFO_PARAM = "info";
+    
+    protected static final String STRUCT_ANCESTORS = "ancestors";
+    protected static final String STRUCT_PARENT = "parent";
+    protected static final String STRUCT_SIBS = "siblings";
+    protected static final String STRUCT_CHILDREN = "children";
+    protected static final String STRUCT_DESCENDS = "descendants";
+    protected static final String STRUCT_ENTIRE = "entire";
+
+    protected static final String INFO_NUM_SIBS = "numSiblings";
+    protected static final String INFO_NUM_CHILDREN = "numChildren";
+    protected static final String INFO_SIB_POS = "siblingPosition";
+
+    // means the id is not a greenstone id and needs translating
+    protected static final String EXTID_PARAM = "ext"; 
+    
+    protected Element config_info = null; // the xml from the config file
+
+    protected String default_document_type = null;
+    protected MacroResolver macro_resolver = null;
+
+    /** does this class provide the service?? */
+    protected boolean does_metadata = true;
+    protected boolean does_content = true;
+    protected boolean does_structure = true;
+
+    /** constructor */
+    public AbstractDocumentRetrieve()
+    {
+    }
+
+    /** configure this service */
+    public boolean configure(Element info, Element extra_info)
+    {
+	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+
+	logger.info("Configuring AbstractDocumentRetrieve...");
+	this.config_info = info;
+
+	// set up short_service_info_ - for now just has name and type
+	if (does_structure) {
+	    Element dsr_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    dsr_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
+	    dsr_service.setAttribute(GSXML.NAME_ATT, DOCUMENT_STRUCTURE_RETRIEVE_SERVICE);
+	    this.short_service_info.appendChild(dsr_service);
+	}
+
+	if (does_metadata) {
+	    Element dmr_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    dmr_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
+	    dmr_service.setAttribute(GSXML.NAME_ATT, DOCUMENT_METADATA_RETRIEVE_SERVICE);
+	    this.short_service_info.appendChild(dmr_service);
+	}
+
+	if (does_content) {
+	    Element dcr_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    dcr_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
+	    dcr_service.setAttribute(GSXML.NAME_ATT, DOCUMENT_CONTENT_RETRIEVE_SERVICE);
+	    this.short_service_info.appendChild(dcr_service);
+	}
+	
+	// look for document display format
+	String path = GSPath.appendLink(GSXML.DISPLAY_ELEM, GSXML.FORMAT_ELEM);
+	Element display_format = (Element)GSXML.getNodeByPath(extra_info, path);
+	if (display_format != null) {
+	    this.format_info_map.put(DOCUMENT_CONTENT_RETRIEVE_SERVICE, this.doc.importNode(display_format, true));
+	    // should we keep a copy?
+	    // check for docType option.
+	    Element doc_type_opt = GSXML.getNamedElement(display_format, "gsf:option", GSXML.NAME_ATT, "documentType");
+	    if (doc_type_opt != null) {
+		String value = doc_type_opt.getAttribute(GSXML.VALUE_ATT);
+		if (!value.equals("")) {
+		    this.default_document_type = value;
+		}
+	    }
+	}
+
+	if (macro_resolver != null) {
+	    macro_resolver.setSiteDetails(this.site_http_address, this.cluster_name);
+	    // set up the macro resolver
+	    Element replacement_elem = (Element)GSXML.getChildByTagName(extra_info, "replaceList");
+	    if (replacement_elem != null) {
+		macro_resolver.addMacros(replacement_elem);
+	    }
+	    // look for any refs to global replace lists
+	    NodeList replace_refs_elems = extra_info.getElementsByTagName("replaceListRef");
+	    for (int i=0; i<replace_refs_elems.getLength(); i++) {
+		String id = ((Element)replace_refs_elems.item(i)).getAttribute("id");
+		if (!id.equals("")) {
+		    Element replace_list = GSXML.getNamedElement(this.router.config_info, "replaceList", "id", id);
+		    if (replace_list != null) {
+			macro_resolver.addMacros(replace_list);
+		    }
+		}
+	    }
+	}
+	
+	return true;
+    }
+    
+    protected Element getServiceDescription(String service_id, String lang, String subset) {
+	
+	// these ones are probably never called, but put them here just in case
+	Element service_elem = this.doc.createElement(GSXML.SERVICE_ELEM);
+	service_elem.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
+	service_elem.setAttribute(GSXML.NAME_ATT, service_id);
+	return service_elem;
+    }
+
+    protected Element processDocumentMetadataRetrieve(Element request) {
+
+	// Create a new (empty) result message
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	result.setAttribute(GSXML.FROM_ATT, DOCUMENT_METADATA_RETRIEVE_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+
+	if (!does_metadata) {
+	    // shouldn't get here
+	    return result;
+	}
+
+	// Get the parameters of the request
+	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (param_list == null) {
+	    GSXML.addError(this.doc, result, "DocumentMetadataRetrieve: missing "+ GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER, GSXML.ERROR_TYPE_SYNTAX);
+	    return result;  
+	}
+
+	boolean external_id = false;
+	// The metadata information required
+	ArrayList metadata_names_list = new ArrayList();
+	boolean all_metadata = false;
+	// Process the request parameters
+	Element param = (Element) param_list.getFirstChild();
+	while (param != null) {
+	    // Identify the metadata information desired
+	    if (param.getAttribute(GSXML.NAME_ATT).equals("metadata")) {
+		String metadata = GSXML.getValue(param);
+		if (metadata.equals("all")) {
+		    all_metadata = true;
+		    break;
+		}
+		metadata_names_list.add(metadata);
+	    } else if (param.getAttribute(GSXML.NAME_ATT).equals(EXTID_PARAM)&& GSXML.getValue(param).equals("1")) {
+		external_id = true;
+	    }
+	    param = (Element) param.getNextSibling();
+	}
+
+	// check that there has been some metadata specified
+	if (!all_metadata && metadata_names_list.size()==0) {
+	    GSXML.addError(this.doc, result, "DocumentMetadataRetrieve: no metadata names found in the "+ GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER, GSXML.ERROR_TYPE_SYNTAX);
+	    return result;  
+	}
+
+	// Get the documents
+	Element request_node_list = (Element) GSXML.getChildByTagName(request, GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	if (request_node_list == null) {
+	    GSXML.addError(this.doc, result, "DocumentMetadataRetrieve: missing " +GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER, GSXML.ERROR_TYPE_SYNTAX);
+ 	    return result;
+ 	}
+
+	// copy the request doc node list to the response
+	Element response_node_list = (Element) this.doc.importNode(request_node_list, true);
+	result.appendChild(response_node_list);
+	
+	// use the copied list so that we add the metadata into the copy
+	// are we just adding metadata for the top level nodes? or can we accept a hierarchy here???
+	NodeList request_nodes = GSXML.getChildrenByTagName(response_node_list, GSXML.DOC_NODE_ELEM);
+	if (request_nodes.getLength()==0) {
+	    GSXML.addError(this.doc, result, "DocumentMetadataRetrieve: no "+GSXML.DOC_NODE_ELEM +" found in the "+ GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER, GSXML.ERROR_TYPE_SYNTAX);
+ 	    return result;
+ 	}
+
+	// Whew, now we have checked (almost) all the syntax of the request, now we can process it.
+	
+	for (int i = 0; i < request_nodes.getLength(); i++) {
+	    Element request_node = (Element) request_nodes.item(i);
+	    String node_id = request_node.getAttribute(GSXML.NODE_ID_ATT);
+
+	    if (external_id) {
+		// can we have .pr etc extensions with external ids?
+		node_id = translateExternalId(node_id);
+	    } else if (idNeedsTranslating(node_id)) {
+		node_id = translateId(node_id);
+	    }	    
+	    if (node_id == null) {
+		continue;
+	    }
+	    try {
+		Element metadata_list = getMetadataList(node_id, all_metadata, metadata_names_list);
+		request_node.appendChild(metadata_list);
+	    } catch (GSException e) {		
+		GSXML.addError(this.doc, result, e.getMessage(), e.getType());
+		if (e.getType().equals(GSXML.ERROR_TYPE_SYSTEM)) {
+		    // there is no point trying any others
+		    return result;
+		}
+	    } 
+	}
+		
+	return result;
+    }
+
+    protected Element processDocumentStructureRetrieve(Element request) {
+    
+	// Create a new (empty) result message
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.setAttribute(GSXML.FROM_ATT, DOCUMENT_STRUCTURE_RETRIEVE_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+	
+	if (!does_structure) {
+	    // shouldn't get here
+	    return result;
+	}
+
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+
+	// Get the parameters of the request
+	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (param_list == null) {
+	    GSXML.addError(this.doc, result, "DocumentStructureRetrieve: missing "+ GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER, GSXML.ERROR_TYPE_SYNTAX);
+	    return result;  
+	}
+	
+	// get the documents of the request
+	Element query_doc_list = (Element) GSXML.getChildByTagName(request, GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	if (query_doc_list == null) {
+	    GSXML.addError(this.doc, result, "DocumentStructureRetrieve: missing " +GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER, GSXML.ERROR_TYPE_SYNTAX);
+ 	    return result;
+ 	}
+	
+	// copy the doc_list to the response
+	Element response_node_list = (Element) this.doc.importNode(query_doc_list, true);
+	result.appendChild(response_node_list);
+	
+	// check that we have some doc nodes specified
+	NodeList node_list = GSXML.getChildrenByTagName(response_node_list, GSXML.DOC_NODE_ELEM);
+	if (node_list.getLength()==0) {
+	    GSXML.addError(this.doc, result, "DocumentStructureRetrieve: no "+GSXML.DOC_NODE_ELEM +" found in the "+ GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER, GSXML.ERROR_TYPE_SYNTAX);
+ 	    return result;
+ 	}
+
+	Element extid_param = GSXML.getNamedElement(param_list, GSXML.PARAM_ELEM, GSXML.NAME_ATT, EXTID_PARAM);
+	boolean external_id = false;
+	if (extid_param != null && GSXML.getValue(extid_param).equals("1")) {
+	    external_id = true;
+	}
+
+	// the type of info required
+	boolean want_structure = false;
+	boolean want_info = false;
+
+	ArrayList info_types=new ArrayList();
+	// The document structure information desired
+	boolean want_ancestors = false;
+	boolean want_parent = false;
+	boolean want_siblings = false;
+	boolean want_children = false;
+	boolean want_descendants = false;
+
+	boolean want_entire_structure = false;
+	// Process the request parameters
+	NodeList params = param_list.getElementsByTagName(GSXML.PARAM_ELEM);
+	for (int i=0; i<params.getLength();i++) {
+	    
+	    Element param = (Element)params.item(i);
+	    String p_name = param.getAttribute(GSXML.NAME_ATT);
+	    String p_value = GSXML.getValue(param);
+	    // Identify the structure information desired
+	    if (p_name.equals(STRUCT_PARAM)) {
+		want_structure = true;
+		
+		// This is NOT locale sensitive
+		if (p_value.equals(STRUCT_ANCESTORS))
+		    want_ancestors = true;
+		else if (p_value.equals(STRUCT_PARENT))
+		    want_parent = true;
+		else if (p_value.equals(STRUCT_SIBS))
+		    want_siblings = true;
+		else if (p_value.equals(STRUCT_CHILDREN))
+		    want_children = true;
+		else if (p_value.equals(STRUCT_DESCENDS))
+		    want_descendants = true;
+		else if (p_value.equals(STRUCT_ENTIRE))
+		    want_entire_structure = true;
+		else
+		    logger.error("AbstractDocumentRetrieve Warning: Unknown value \"" + p_value + "\".");
+	    } else if (p_name.equals(INFO_PARAM)) {
+		want_info = true;
+		info_types.add(p_value);
+	    }
+	}
+
+	// Make sure there is no repeated information
+	if (want_ancestors)
+	    want_parent = false;
+	if (want_descendants)
+	    want_children = false;
+
+	for (int i=0; i < node_list.getLength(); i++) {
+	    Element doc = (Element) node_list.item(i);
+	    String doc_id = doc.getAttribute(GSXML.NODE_ID_ATT);
+	    if (external_id) {
+		doc_id = translateExternalId(doc_id);
+		doc.setAttribute(GSXML.NODE_ID_ATT, doc_id);
+	    } else if (idNeedsTranslating(doc_id)) {
+		doc_id = translateId(doc_id);	
+		doc.setAttribute(GSXML.NODE_ID_ATT, doc_id);
+	    }
+	    if (doc_id == null) {
+		continue;
+	    }
+
+	    if (want_info) {
+
+		Element node_info_elem = this.doc.createElement("nodeStructureInfo");
+		doc.appendChild(node_info_elem);
+		
+		for (int j=0; j<info_types.size(); j++) {
+		    String info_type = (String)info_types.get(j);
+		    String info_value = getStructureInfo(doc_id, info_type);
+		    if (info_value != null) {
+			Element info_elem = this.doc.createElement("info");
+			info_elem.setAttribute(GSXML.NAME_ATT, info_type);
+			info_elem.setAttribute(GSXML.VALUE_ATT, info_value);
+			node_info_elem.appendChild(info_elem);
+		    }
+		}
+	    }
+	    
+	    if (want_structure) {
+		// all structure info goes into a nodeStructure elem
+		Element structure_elem = this.doc.createElement(GSXML.NODE_STRUCTURE_ELEM);
+		doc.appendChild(structure_elem);
+		
+		if (want_entire_structure) {
+		    String root_id = getRootId(doc_id);
+		    Element root_node = createDocNode(root_id); //, true, false);
+		    addDescendants(root_node, root_id, true);
+		    structure_elem.appendChild(root_node);
+		    continue; // with the next document, we dont need to do any more here
+		}
+		
+		// Add the requested structure information
+		Element base_node = createDocNode(doc_id); //, false, false);
+		
+		//Ancestors: continually add parent nodes until the root is reached
+		Element top_node = base_node; // the top node so far
+		if (want_ancestors) {
+		    String current_id = doc_id;
+		    while (true) {
+			String parent_id = getParentId(current_id);
+			//Element parent = getParent(current_id);
+			if (parent_id == null)
+			    break; // no parent
+			Element parent_node = createDocNode(parent_id);
+			parent_node.appendChild(top_node);
+			current_id = parent_id;//.getAttribute(GSXML.NODE_ID_ATT);
+			top_node = parent_node;
+		    }
+		}
+		// Parent: get the parent of the selected node
+		else if (want_parent) {
+		    String parent_id = getParentId(doc_id);
+		    if (parent_id != null) {
+			Element parent_node = createDocNode(parent_id);
+			parent_node.appendChild(base_node);
+			top_node = parent_node;
+		    }
+		}
+		
+		// now the top node is the root of the structure
+		structure_elem.appendChild(top_node);
+		
+		//Siblings: get the other descendants of the selected node's parent
+		if (want_siblings) {
+		    String parent_id = getParentId(doc_id);
+		    if (parent_id != null) {
+			// if parent == current id, then we are at the top 
+			// and can't get siblings
+			Element parent_node = (Element)base_node.getParentNode(); // this may be the structure element if there has been no request for parents or ancestors
+		    
+			// add siblings, - returns a pointer to the new current node 
+			base_node = addSiblings(parent_node, parent_id, doc_id);
+		    }
+
+		}
+		
+		// Children: get the descendants, but only one level deep
+		if (want_children) {
+		    addDescendants(base_node, doc_id, false);
+		} 
+		// Descendants: recursively get every descendant 
+		else if (want_descendants) {
+		    addDescendants(base_node, doc_id, true);
+		}
+	    } // if want structure
+	} // for each doc
+	return result;
+    }
+
+    /** Retrieve the content of a document */
+    protected Element processDocumentContentRetrieve(Element request)
+    {
+	// Create a new (empty) result message
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.setAttribute(GSXML.FROM_ATT, DOCUMENT_CONTENT_RETRIEVE_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+	
+	if (!does_content) {
+	    // shouldn't get here
+	    return result;
+	}
+
+	// Get the parameters of the request
+  	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	Element extid_param = GSXML.getNamedElement(param_list, GSXML.PARAM_ELEM, GSXML.NAME_ATT, EXTID_PARAM);
+	boolean external_id = false;
+	if (extid_param != null && GSXML.getValue(extid_param).equals("1")) {
+	    external_id = true;
+	}
+	// Get the request content 
+	Element query_doc_list = (Element) GSXML.getChildByTagName(request, GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	if (query_doc_list == null) {
+	    logger.error("Error: DocumentContentRetrieve request specified no doc nodes.\n");
+	    return result;
+	}
+	
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	Element doc_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(doc_list);
+	
+	// set up the retrieval??
+
+	// Get the documents
+	String[] doc_ids = GSXML.getAttributeValuesFromList(query_doc_list, 
+							    GSXML.NODE_ID_ATT);
+	for (int i = 0; i < doc_ids.length; i++) {
+	    String doc_id = doc_ids[i];
+	    // Create the document node
+	    Element doc = this.doc.createElement(GSXML.DOC_NODE_ELEM);
+	    doc.setAttribute(GSXML.NODE_ID_ATT, doc_id);
+	    doc_list.appendChild(doc);
+
+	    if (external_id) {
+		doc_id = translateExternalId(doc_id);
+		doc.setAttribute(GSXML.NODE_ID_ATT, doc_id);
+	    } else if (idNeedsTranslating(doc_id)) {
+		doc_id = translateId(doc_id);
+		doc.setAttribute(GSXML.NODE_ID_ATT, doc_id);
+	    }
+	    if (doc_id == null) {
+		continue;
+	    }
+	    try {
+		Element node_content = getNodeContent(doc_id, lang);
+		doc.appendChild(node_content);
+	    } catch (GSException e) {
+		GSXML.addError(this.doc, result, e.getMessage());
+		return result;
+		
+	    }
+	}
+	return result;
+    }
+    
+    /** create an element to go into the structure. A node element
+     * has the form
+     * <docNode nodeId='xxx' nodeType='leaf' docType='hierarchy'/>
+     */
+    protected Element createDocNode(String node_id) {
+	Element node = this.doc.createElement(GSXML.DOC_NODE_ELEM);
+	node.setAttribute(GSXML.NODE_ID_ATT, node_id);
+
+	String doc_type = null;
+	if (default_document_type != null) {
+	    doc_type = default_document_type;
+	} else {
+	    doc_type = getDocType(node_id);
+	}
+	node.setAttribute(GSXML.DOC_TYPE_ATT, doc_type);
+	String node_type = getNodeType(node_id, doc_type);	
+	node.setAttribute(GSXML.NODE_TYPE_ATT, node_type);
+	return node;
+    }
+
+    /** adds all the children of doc_id the the doc element,
+     * and if recursive=true, adds all their children as well*/
+    protected void addDescendants(Element doc, String doc_id, 
+				  boolean recursive)
+    {
+	ArrayList child_ids = getChildrenIds(doc_id);
+	if (child_ids==null) return;
+	for (int i=0; i< child_ids.size(); i++) {
+	    String child_id = (String)child_ids.get(i);
+	    Element child_elem = createDocNode(child_id);
+	    doc.appendChild(child_elem);
+	    if (recursive && !child_elem.getAttribute(GSXML.NODE_TYPE_ATT).equals(GSXML.NODE_TYPE_LEAF)) {
+		addDescendants(child_elem, child_id, recursive);
+	    }
+	}
+    }
+
+    /** adds all the siblings of current_id to the parent element. 
+      returns the new current element*/
+    protected Element addSiblings(Element parent_node, String parent_id, 
+				  String current_id) {
+	Element current_node = (Element)parent_node.getFirstChild();
+	if (current_node == null) {
+	    // create a sensible error message
+	    logger.error(" there should be a first child.");
+	    return null;
+	}
+	// remove the current child,- will add it in later in its correct place
+	parent_node.removeChild(current_node);
+
+	// add in all the siblings,
+	addDescendants(parent_node, parent_id, false);
+
+	// find the node that is now the current node
+	// this assumes that the new node that was created is the same as 
+	// the old one that was removed - we may want to replace the new one 
+	// with the old one.
+	Element new_current = GSXML.getNamedElement(parent_node, current_node.getNodeName(), GSXML.NODE_ID_ATT, current_id);
+	return new_current;
+    }
+
+    /** returns true if oid ends in
+	.fc (firstchild), 
+	.lc (lastchild), 
+	.pr (parent), 
+	.ns (next sibling), 
+	.ps (prev sibling), 
+	.rt (root) 
+	.ss (specified sibling), 
+	false otherwise 
+    */
+    protected boolean idNeedsTranslating(String id) {
+	return OID.needsTranslating(id);
+    }
+
+    /** returns the list of sibling ids, including the specified node_id */
+    protected ArrayList getSiblingIds(String node_id) {
+	String parent_id = getParentId(node_id);
+	if (parent_id == null) {
+	    return null;
+	}
+	return getChildrenIds(parent_id);
+
+    }
+
+   /** returns the node type of the specified node.
+	should be one of 
+	GSXML.NODE_TYPE_LEAF, 
+	GSXML.NODE_TYPE_INTERNAL, 
+	GSXML.NODE_TYPE_ROOT
+    */
+    protected String getNodeType(String node_id, String doc_type) {
+	if (doc_type.equals(GSXML.DOC_TYPE_SIMPLE)) {
+	    return GSXML.NODE_TYPE_LEAF;
+	}
+
+	if (getParentId(node_id)==null) {
+	    return GSXML.NODE_TYPE_ROOT;
+	}
+	if (doc_type.equals(GSXML.DOC_TYPE_PAGED)) {
+	     return GSXML.NODE_TYPE_LEAF;
+	}
+	if (getChildrenIds(node_id)==null) {
+	    return GSXML.NODE_TYPE_LEAF;
+	}
+	return GSXML.NODE_TYPE_INTERNAL;	
+	
+    }
+
+    /** if id ends in .fc, .pc etc, then translate it to the correct id 
+     * default implementation: just remove the suffix */
+    protected String translateId(String id) {
+	return id.substring(0,id.length());
+    }
+    
+    /** if an id is not a greenstone id (an external id) then translate 
+     * it to a greenstone one 
+     * default implementation: return the id */
+    protected String translateExternalId(String id) {
+	return id;
+    }
+
+    /** returns the document type of the doc that the specified node 
+	belongs to. should be one of 
+	GSXML.DOC_TYPE_SIMPLE, 
+	GSXML.DOC_TYPE_PAGED, 
+	GSXML.DOC_TYPE_HIERARCHY
+	default implementation: return DOC_TYPE_SIMPLE
+    */
+    protected String getDocType(String node_id) {
+	return GSXML.DOC_TYPE_SIMPLE;
+    }
+	
+
+    /** returns the id of the root node of the document containing 
+     * node node_id. may be the same as node_id 
+     * default implemntation: return node_id
+    */
+    protected String getRootId(String node_id) {
+	return node_id;
+    }
+    /** returns a list of the child ids in order, null if no children 
+     * default implementation: return null */
+    protected ArrayList getChildrenIds(String node_id) {
+	return null;
+    }
+    /** returns the node id of the parent node, null if no parent 
+     * default implementation: return null */
+    protected String getParentId(String node_id) {
+	return null;
+    }
+
+    /** get the metadata for the doc node doc_id
+     * returns a metadataList element:
+     * <metadataList><metadata name="xxx">value</metadata></metadataList>
+     */
+    abstract protected Element getMetadataList(String doc_id, 
+					       boolean all_metadata, 
+					       ArrayList metadata_names) throws GSException;
+    /** returns the content of a node
+     * should return a nodeContent element:
+     * <nodeContent>text content or other elements</nodeContent>
+     * can return 
+     */
+    abstract protected Element getNodeContent(String doc_id, String lang) throws GSException;
+
+    /** returns the structural information asked for.
+     * info_type may be one of
+     * INFO_NUM_SIBS, INFO_NUM_CHILDREN, INFO_SIB_POS
+     */
+    abstract protected String getStructureInfo(String doc_id, String info_type);
+    
+}   
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/AbstractGS2DocumentRetrieve.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/AbstractGS2DocumentRetrieve.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/AbstractGS2DocumentRetrieve.java	(revision 14125)
@@ -0,0 +1,474 @@
+/*
+ *    AbstractGS2DocumentRetrieve.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.service;
+
+// Greenstone classes
+import org.greenstone.gsdl3.core.GSException;
+import org.greenstone.gsdl3.util.GSXML;
+import org.greenstone.gsdl3.util.GSFile;
+import org.greenstone.gsdl3.util.OID;
+import org.greenstone.gsdl3.util.MacroResolver;
+import org.greenstone.gsdl3.util.GS2MacroResolver;
+import org.greenstone.gsdl3.util.GSConstants;
+import org.greenstone.gsdl3.util.GDBMWrapper;
+import org.greenstone.gsdl3.util.DBInfo;
+// XML classes
+import org.w3c.dom.Document;
+import org.w3c.dom.Element; 
+import org.w3c.dom.NodeList;
+
+// General Java classes
+import java.io.File;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import java.util.Set;
+import java.util.Iterator;
+import java.util.ArrayList;
+
+import org.apache.log4j.*;
+
+/** Implements the generic retrieval and classifier services for GS2 
+ * collections.
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @author <a href="mailto:mdewsnip@cs.waikato.ac.nz">Michael Dewsnip</a>
+ */
+
+public abstract class AbstractGS2DocumentRetrieve
+    extends AbstractDocumentRetrieve {
+
+      static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.AbstractGS2DocumentRetrieve.class.getName());
+
+    //    protected static final String EXTLINK_PARAM = "ext"; here or in base??    
+    protected String index_stem = null;
+
+    protected GDBMWrapper gdbm_src = null;
+
+
+    /** constructor */
+    protected AbstractGS2DocumentRetrieve()
+    {
+	this.gdbm_src = new GDBMWrapper();
+	this.macro_resolver = new GS2MacroResolver(this.gdbm_src);
+    }
+
+    public void cleanUp() {
+	super.cleanUp();
+	this.gdbm_src.closeDatabase();
+    }
+    /** configure this service */
+    public boolean configure(Element info, Element extra_info)
+    {
+	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+	
+	logger.info("Configuring AbstractGS2DocumentRetrieve...");
+	//this.config_info = info;
+	
+	// the index stem is either specified in the config file or is  the collection name
+	Element index_stem_elem = (Element) GSXML.getChildByTagName(info, GSXML.INDEX_STEM_ELEM);
+	if (index_stem_elem != null) {
+	    this.index_stem = index_stem_elem.getAttribute(GSXML.NAME_ATT);
+	}
+	if (this.index_stem == null || this.index_stem.equals("")) {
+	    logger.error("AbstractGS2DocumentRetrieve.configure(): indexStem element not found, stem will default to collection name");
+	    this.index_stem = this.cluster_name;
+	}
+
+	// Open GDBM database for querying
+	String gdbm_db_file = GSFile.GDBMDatabaseFile(this.site_home, this.cluster_name, this.index_stem);
+	if (!this.gdbm_src.openDatabase(gdbm_db_file, GDBMWrapper.READER)) {
+	    logger.error("Could not open GDBM database!");
+	    return false;
+	}
+
+	return true;
+    }
+
+    /** if id ends in .fc, .pc etc, then translate it to the correct id */
+    protected String translateId(String node_id) {
+	return this.gdbm_src.translateOID(node_id);
+    }
+    
+    /** if an id is not a greenstone id (an external id) then translate 
+	it to a greenstone one*/
+    protected String translateExternalId(String node_id){
+	return this.gdbm_src.externalId2OID(node_id);
+    }
+
+    /** returns the id of the root node of the document containing node node_id. . may be the same as node_id */
+    protected String getRootId(String node_id) {
+	return OID.getTop(node_id);
+    }
+    /** returns a list of the child ids in order, null if no children */
+    protected ArrayList getChildrenIds(String node_id) {
+	DBInfo info = this.gdbm_src.getInfo(node_id);
+	if (info == null) {
+	    return null;
+	}
+
+	String contains = info.getInfo("contains");
+	if (contains.equals("")) {
+	    return null;
+	}
+	ArrayList children = new ArrayList();
+	StringTokenizer st = new StringTokenizer(contains, ";");
+	while (st.hasMoreTokens()) {
+	    String child_id = st.nextToken().replaceAll("\"", node_id);
+	    children.add(child_id);
+	}
+	return children;
+
+    }
+    /** returns the node id of the parent node, null if no parent */
+    protected String getParentId(String node_id){
+	String parent = OID.getParent(node_id);
+	if (parent.equals(node_id)) {
+	    return null;
+	}
+	return parent;
+    }
+
+    /** get the metadata for the classifier node node_id
+     * returns a metadataList element:
+     * <metadataList><metadata name="xxx">value</metadata></metadataList>
+     */
+    // assumes only one value per metadata
+    protected Element getMetadataList(String node_id, boolean all_metadata,
+				      ArrayList metadata_names)  
+	throws GSException {
+	Element metadata_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+	DBInfo info = this.gdbm_src.getInfo(node_id);
+	if (info == null) {
+	    return null;
+	}
+	String lang = "en"; // why do we need this??
+	if (all_metadata) {
+	    // return everything out of the database
+	    Set keys = info.getKeys();
+	    Iterator it = keys.iterator();
+	    while(it.hasNext()) {
+		String key = (String)it.next();
+		//String value = info.getInfo(key);
+		Vector values = info.getMultiInfo(key);
+		for(int i=0; i<values.size(); i++) {
+		    GSXML.addMetadata(this.doc, metadata_list, key, this.macro_resolver.resolve((String)values.elementAt(i), lang, MacroResolver.SCOPE_META, node_id));
+		}
+	    }
+	    
+	} else {
+	    for (int i=0; i<metadata_names.size(); i++) {
+                String meta_name = (String) metadata_names.get(i);
+		String value = getMetadata(node_id, info, meta_name, lang);
+		GSXML.addMetadata(this.doc, metadata_list, meta_name, value);
+	    }
+	}
+	return metadata_list;
+    }
+
+    /** returns the structural information asked for.
+     * info_type may be one of
+     * INFO_NUM_SIBS, INFO_NUM_CHILDREN, INFO_SIB_POS
+     */
+    protected String getStructureInfo(String doc_id, String info_type) {
+	String value="";
+	if (info_type.equals(INFO_NUM_SIBS)) {
+	    String parent_id = OID.getParent(doc_id);
+	    if (parent_id.equals(doc_id)) {
+		value="0";
+	    } else {
+		value = String.valueOf(getNumChildren(parent_id));
+	    }
+	    return value;
+	}
+	
+	if (info_type.equals(INFO_NUM_CHILDREN)) {
+	    return String.valueOf(getNumChildren(doc_id));
+	}
+
+	
+	if (info_type.equals(INFO_SIB_POS)) {
+	    String parent_id = OID.getParent(doc_id);
+	    if (parent_id.equals(doc_id)) {
+		return "-1";
+	    }
+	    
+	    DBInfo info = this.gdbm_src.getInfo(parent_id);
+	    if (info==null) {
+		return "-1";
+	    }
+	    
+	    String contains = info.getInfo("contains");
+	    contains = contains.replaceAll("\"", parent_id);
+	    String [] children = contains.split(";");
+	    for (int i=0;i<children.length;i++) {
+		String child_id = children[i];
+		if (child_id.equals(doc_id)) {
+		    return String.valueOf(i+1); // make it from 1 to length
+			   
+		}
+	    }
+	    
+	    return "-1";
+	} else {
+	    return null;
+	}
+
+    }
+
+    protected int getNumChildren(String node_id) {
+	DBInfo info = this.gdbm_src.getInfo(node_id);
+	if (info == null) {
+	    return 0;
+	}
+	String contains = info.getInfo("contains");
+	if (contains.equals("")) {
+	    return 0;
+	}
+	String [] children = contains.split(";");
+	return children.length;
+    }
+    
+    /** returns the document type of the doc that the specified node 
+	belongs to. should be one of 
+	GSXML.DOC_TYPE_SIMPLE, 
+	GSXML.DOC_TYPE_PAGED, 
+	GSXML.DOC_TYPE_HIERARCHY
+    */
+    protected String getDocType(String node_id) {
+	DBInfo info = this.gdbm_src.getInfo(node_id);
+	if (info == null) {
+	    return GSXML.DOC_TYPE_SIMPLE;
+	}
+	String doc_type = info.getInfo("doctype");
+	if (!doc_type.equals("")&&!doc_type.equals("doc")) {
+	    return doc_type;
+	}
+
+	String top_id = OID.getTop(node_id);
+	boolean is_top = (top_id.equals(node_id) ? true : false);
+	
+	String children = info.getInfo("contains");
+	boolean is_leaf = (children.equals("") ? true : false);
+
+	if (is_top && is_leaf) { // a single section document
+	    return GSXML.DOC_TYPE_SIMPLE;
+	}
+
+	// now we just check the top node
+	if (!is_top) { // we need to look at the top info
+	    info = this.gdbm_src.getInfo(top_id);
+	}
+	if (info == null) {
+	    return GSXML.DOC_TYPE_HIERARCHY;
+	}
+ 
+	String childtype = info.getInfo("childtype");
+	if (childtype.equals("Paged")) {
+	    return GSXML.DOC_TYPE_PAGED;
+	}
+	return GSXML.DOC_TYPE_HIERARCHY;
+    }
+
+    /** returns the content of a node
+     * should return a nodeContent element:
+     * <nodeContent>text content or other elements</nodeContent>
+     */
+    abstract protected Element getNodeContent(String doc_id, String lang) throws GSException;
+
+    protected String getMetadata(String node_id, DBInfo info, 
+				 String metadata, String lang) {
+	boolean multiple = false;
+	String relation = "";
+	String separator = ", ";
+	int pos = metadata.indexOf(GSConstants.META_RELATION_SEP);
+	if (pos ==-1) {
+              Vector values = info.getMultiInfo(metadata);        
+                   
+  	    // just a plain meta entry eg dc.Title
+	     StringBuffer result = new StringBuffer(); 
+	     boolean first = true;
+	     for (int i=0; i<values.size(); i++) {
+		 if (first) {
+		     first = false;
+		 } else {
+		     result.append(separator);
+		 }
+		 result.append(this.macro_resolver.resolve((String)values.elementAt(i), lang, MacroResolver.SCOPE_META, node_id)); 
+	     }
+	     return result.toString();
+	}
+
+	String temp = metadata.substring(0, pos);
+	metadata = metadata.substring(pos+1);
+	// check for all on the front
+	if (temp.equals("all")) {
+	    multiple=true;	    
+	    pos = metadata.indexOf(GSConstants.META_RELATION_SEP);
+	    if (pos ==-1) {
+		temp = "";
+	    } else {
+		temp = metadata.substring(0, pos);
+		metadata = metadata.substring(pos+1);
+	    }
+	}
+	
+	// now check for relational info
+	if (temp.equals("parent") || temp.equals("root") || temp.equals( "ancestors")) { // "current" "siblings" "children" "descendents"
+	    relation = temp;
+	    pos = metadata.indexOf(GSConstants.META_RELATION_SEP);
+	    if (pos == -1) {
+		temp = "";
+	    } else {
+		temp = metadata.substring(0, pos);
+		metadata = metadata.substring(pos+1);
+	    }
+	}
+	
+	// now look for separator info
+	if (temp.startsWith(GSConstants.META_SEPARATOR_SEP) && temp.endsWith(GSConstants.META_SEPARATOR_SEP)) {
+	    separator = temp.substring(1, temp.length()-1);
+	    
+	}
+	
+	String relation_id = node_id;
+	if (relation.equals("parent") || relation.equals("ancestors")) {
+	    relation_id = OID.getParent(node_id);
+	    // parent or ancestor does not include self
+	    if (relation_id.equals(node_id)){
+		return "";
+	    }
+	} else if (relation.equals("root")) {
+	    relation_id = OID.getTop(node_id);
+	}
+	
+	// now we either have a single node, or we have ancestors	
+	DBInfo relation_info;
+	if (relation_id.equals(node_id)) {
+	    relation_info = info;
+	} else {
+	    relation_info = this.gdbm_src.getInfo(relation_id);
+	}
+	if (relation_info == null) {
+	    return "";
+	}
+
+	StringBuffer result = new StringBuffer();
+
+	if (!multiple) {
+	    result.append(this.macro_resolver.resolve(relation_info.getInfo(metadata), lang, MacroResolver.SCOPE_META, relation_id));
+	} else {
+	    // we have multiple meta
+	    Vector values = relation_info.getMultiInfo(metadata);
+  	    if (values != null) {
+		boolean first = true;
+		for (int i=0; i<values.size(); i++) {
+		    if (first) {
+			first = false;
+		    } else {
+			result.append(separator);
+		    }
+		    result.append(this.macro_resolver.resolve((String)values.elementAt(i), lang, MacroResolver.SCOPE_META, relation_id));
+		}
+	    }
+          logger.info(result); 
+	}
+	// if not ancestors, then this is all we do
+	if (!relation.equals("ancestors")) {
+	    return result.toString();
+	}
+	
+	// now do the ancestors 
+	String current_id = relation_id;
+	relation_id = OID.getParent(current_id);
+	while (!relation_id.equals(current_id)) {
+	    relation_info = this.gdbm_src.getInfo(relation_id);
+	    if (relation_info == null) return result.toString();
+	    if (!multiple) {
+		result.insert(0, separator);
+		result.insert(0, this.macro_resolver.resolve(relation_info.getInfo(metadata), lang, MacroResolver.SCOPE_META, relation_id));
+	    } else {
+		Vector values = relation_info.getMultiInfo(metadata);
+		if (values != null) {
+		    for (int i=values.size()-1; i>=0; i--) {
+			result.insert(0, separator);
+			result.insert(0, this.macro_resolver.resolve((String)values.elementAt(i), lang, MacroResolver.SCOPE_META, relation_id));
+		    }
+		}
+		
+	    }
+	    current_id = relation_id;
+	    relation_id = OID.getParent(current_id);
+	} 
+	return result.toString();
+    }
+    
+
+    /** needs to get info from gdbm database - if the calling code gets it already it may pay to pass it in instead */
+    protected String resolveTextMacros(String doc_content, String doc_id, String lang)
+    {
+	// resolve any collection specific macros
+	doc_content = macro_resolver.resolve(doc_content, lang, MacroResolver.SCOPE_TEXT, doc_id);
+	return doc_content;
+    }
+
+    protected Element getInfo(String doc_id, String info_type) {
+
+	String value="";
+	if (info_type.equals(INFO_NUM_SIBS)) {
+	    String parent_id = OID.getParent(doc_id);
+	    if (parent_id.equals(doc_id)) {
+		value="0";
+	    } else {
+		value = String.valueOf(getNumChildren(parent_id));
+	    }
+	} else if (info_type.equals(INFO_NUM_CHILDREN)) {
+	    value = String.valueOf(getNumChildren(doc_id));
+	} else if (info_type.equals(INFO_SIB_POS)) {
+	    String parent_id = OID.getParent(doc_id);
+	    if (parent_id.equals(doc_id)) {
+		value="-1";
+	    } else {
+		DBInfo info = this.gdbm_src.getInfo(parent_id);
+		if (info==null) {
+		    value ="-1";
+		} else {
+		    String contains = info.getInfo("contains");
+		    contains = contains.replaceAll("\"", parent_id);
+		    String [] children = contains.split(";");
+		    for (int i=0;i<children.length;i++) {
+			String child_id = children[i];
+			if (child_id.equals(doc_id)) {
+			    value = String.valueOf(i+1); // make it from 1 to length
+			    break;
+			}
+		    }
+		}
+	    }
+	} else {
+	    return null;
+	}
+	Element info_elem = this.doc.createElement("info");
+	info_elem.setAttribute(GSXML.NAME_ATT, info_type);
+	info_elem.setAttribute(GSXML.VALUE_ATT, value);
+	return info_elem;
+    }
+
+}   
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/AbstractGS2FieldSearch.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/AbstractGS2FieldSearch.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/AbstractGS2FieldSearch.java	(revision 14125)
@@ -0,0 +1,658 @@
+/*
+ *    AbstractGS2FieldSearch.java
+ *    Copyright (C) 2006 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *   the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.service;
+
+
+// Greenstone classes
+import org.greenstone.mgpp.*;
+import org.greenstone.gsdl3.util.*;
+
+// XML classes
+import org.w3c.dom.Document;
+import org.w3c.dom.Element; 
+import org.w3c.dom.NodeList;
+
+// java classes
+import java.util.Iterator;
+import java.util.Set;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ArrayList;
+import java.util.Vector;
+import java.io.File;
+
+import org.apache.log4j.*;
+
+
+abstract public class AbstractGS2FieldSearch 
+    extends AbstractGS2Search 
+{
+
+    // extra services offered by mgpp collections
+    protected static final String FIELD_QUERY_SERVICE = "FieldQuery";
+    protected static final String ADVANCED_FIELD_QUERY_SERVICE = "AdvancedFieldQuery";
+
+    // extra parameters used
+    protected static final String LEVEL_PARAM = "level";
+    protected static final String RANK_PARAM = "sortBy";
+    protected static final String RANK_PARAM_RANK = "1";
+    protected static final String RANK_PARAM_NONE = "0";
+    protected static final String SIMPLE_FIELD_PARAM = "simpleField";
+    protected static final String ADVANCED_FIELD_PARAM = "complexField";
+
+    // more params for field query
+    protected static final String FIELD_QUERY_PARAM = "fqv";
+    protected static final String FIELD_STEM_PARAM = "fqs";
+    protected static final String FIELD_CASE_PARAM = "fqc";
+    protected static final String FIELD_ACCENT_PARAM="fqa";
+    protected static final String FIELD_FIELD_PARAM = "fqf";
+    protected static final String FIELD_COMBINE_PARAM = "fqk";
+    protected static final String FIELD_COMBINE_PARAM_AND = "0";
+    protected static final String FIELD_COMBINE_PARAM_OR = "1";
+    protected static final String FIELD_COMBINE_PARAM_NOT = "2";
+
+    // some stuff for config files
+    protected static final String SEARCH_TYPE_ELEM = "searchType";
+    protected static final String SEARCH_TYPE_PLAIN = "plain";
+    protected static final String SEARCH_TYPE_FORM = "form";
+    protected static final String SEARCH_TYPE_FORM_SIMPLE = "simple";
+    protected static final String SEARCH_TYPE_FORM_ADVANCED = "advanced";
+
+    protected static final String DEFAULT_LEVEL_ELEM = "defaultLevel";
+    protected static final String DEFAULT_GDBM_LEVEL_ELEM = "defaultGDBMLevel";
+    protected static final String LEVEL_ELEM = "level";
+    protected static final String FIELD_ATT = "field";
+
+
+    protected static final int TEXT_QUERY = 0;
+    protected static final int SIMPLE_QUERY = 1;
+    protected static final int ADVANCED_QUERY = 2;
+
+    protected String AND_OPERATOR = "&";
+    protected String OR_OPERATOR = "|";
+    protected String NOT_OPERATOR = "!";
+    
+   // the default level for searching
+    protected String default_level=null;
+    // default level for gdbm db
+    protected String default_gdbm_level = null;
+    // which search services will we offer??
+    protected boolean plain_search = false;
+    protected boolean simple_form_search = false;
+    protected boolean advanced_form_search = false;
+
+
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.AbstractGS2FieldSearch.class.getName());
+
+    /** constructor */
+    public AbstractGS2FieldSearch()
+    {
+    }
+
+    public void cleanUp() {
+	super.cleanUp();
+    }
+
+    /** configure this service */
+    public boolean configure(Element info, Element extra_info)
+    {
+	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+	// the generic config has set up the text query service, but we may not want it
+	Element search_type_list = (Element) GSXML.getChildByTagName(info, SEARCH_TYPE_ELEM + GSXML.LIST_MODIFIER);
+	if (search_type_list == null) {
+	    // assume form and plain
+	    this.plain_search = true;
+	    this.simple_form_search = true;
+	    this.advanced_form_search = true;
+	} else {
+	    NodeList types = search_type_list.getElementsByTagName(SEARCH_TYPE_ELEM);
+	    for (int i=0; i<types.getLength(); i++) {
+		Element t = (Element)types.item(i);
+		String type_name = t.getAttribute(GSXML.NAME_ATT);
+		if (type_name.equals(SEARCH_TYPE_PLAIN)) {
+		    this.plain_search = true;
+		} else if (type_name.equals(SEARCH_TYPE_FORM)) {
+		    String type_type = t.getAttribute(GSXML.TYPE_ATT);
+		    if (type_type.equals("")) {
+			this.simple_form_search = true;
+			this.advanced_form_search = true;
+		    } else if (type_type.equals(SEARCH_TYPE_FORM_SIMPLE)) {
+			this.simple_form_search = true;
+		    } else if (type_type.equals(SEARCH_TYPE_FORM_ADVANCED)) {
+			this.advanced_form_search = true;
+			
+		    }
+		}
+	    }
+	}
+
+	if (!this.plain_search) {
+	    // need to remove the TextQuery service
+	    Element tq_service = GSXML.getNamedElement(short_service_info, GSXML.SERVICE_ELEM, GSXML.NAME_ATT, TEXT_QUERY_SERVICE);
+	    short_service_info.removeChild(tq_service);
+	    
+	}
+
+       
+	// Get the default level out of <defaultLevel> (buildConfig.xml)
+	Element def = (Element) GSXML.getChildByTagName(info, DEFAULT_LEVEL_ELEM);
+	if (def != null) {
+	    this.default_level = def.getAttribute(GSXML.SHORTNAME_ATT);
+	}
+	if (this.default_level == null || this.default_level.equals("")) {
+	    logger.error("default level not specified!, assuming Doc");
+	    this.default_level = "Doc";
+	}
+
+	// Get the default GDBM level
+	def = (Element) GSXML.getChildByTagName(info, DEFAULT_GDBM_LEVEL_ELEM);
+	if (def != null) {
+	    this.default_gdbm_level = def.getAttribute(GSXML.SHORTNAME_ATT);
+	}
+	if (this.default_gdbm_level == null || this.default_gdbm_level.equals("")) {
+	    logger.error("default gdbm level not specified!, assuming Sec");
+	    this.default_gdbm_level = "Sec";
+	}
+	
+	// get display info from extra info - for levels
+	if (extra_info !=null) {
+	    Document owner = info.getOwnerDocument();
+    
+	    NodeList levels = info.getElementsByTagName(GSXML.LEVEL_ELEM);
+	    Element config_search = (Element)GSXML.getChildByTagName(extra_info, GSXML.SEARCH_ELEM);
+	    
+	    for (int i=0; i<levels.getLength();i++) {
+		Element lev = (Element)levels.item(i);
+		String name = lev.getAttribute(GSXML.NAME_ATT);
+		Element node_extra = GSXML.getNamedElement(config_search,
+							   GSXML.LEVEL_ELEM,
+							   GSXML.NAME_ATT,
+							   name);
+		if (node_extra == null) {
+		    logger.error("haven't found extra info for level named "+name);
+		    continue;
+		}
+		
+		// get the display elements if any - displayName
+		NodeList display_names = node_extra.getElementsByTagName(GSXML.DISPLAY_TEXT_ELEM);
+		if (display_names !=null) {
+		    for (int j=0; j<display_names.getLength(); j++) {
+			Element e = (Element)display_names.item(j);
+			lev.appendChild(owner.importNode(e, true));
+		    }
+		}
+	    } // for each level
+	}
+ 
+	// the format info is the same for all services
+	Element format_info = (Element)format_info_map.get(TEXT_QUERY_SERVICE);
+	
+	// set up the extra services which are available for this collection
+	if (this.simple_form_search) {
+	    // set up short_service_info_ - for now just has id and type - name will be added in on the fly
+	    Element fq_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    fq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
+	    fq_service.setAttribute(GSXML.NAME_ATT, FIELD_QUERY_SERVICE);
+	    this.short_service_info.appendChild(fq_service);
+
+	    if (format_info != null) {
+		this.format_info_map.put(FIELD_QUERY_SERVICE, format_info);
+	    }
+	}
+	
+	if (this.advanced_form_search) {
+	    Element afq_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    afq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
+	    afq_service.setAttribute(GSXML.NAME_ATT, ADVANCED_FIELD_QUERY_SERVICE);
+	    this.short_service_info.appendChild(afq_service);
+	    
+	    if (format_info != null) {
+		this.format_info_map.put(ADVANCED_FIELD_QUERY_SERVICE, format_info);
+	    }
+	}
+
+	return true;
+    }
+
+
+    protected Element getServiceDescription(String service_id, String lang, String subset) {
+	// should we check that the service is actually on offer? presumably we wont get asked for services that we haven't advertised previously.
+	
+	if (!service_id.equals(FIELD_QUERY_SERVICE) && !service_id.equals(ADVANCED_FIELD_QUERY_SERVICE)) {
+	    return super.getServiceDescription(service_id, lang, subset);
+	}
+	
+	
+	Element service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
+	service.setAttribute(GSXML.NAME_ATT, service_id);
+	if (subset == null || subset.equals(GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER)) {
+	    service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_NAME, getTextString(service_id+".name", lang)));
+	    service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_SUBMIT, getTextString(service_id+".submit", lang)));
+	    service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_DESCRIPTION, getTextString(service_id+".description", lang)));
+	
+	}
+	if (subset == null || subset.equals(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER)) {
+	    Element param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);	
+	    service.appendChild(param_list);
+	    if (service_id.equals(FIELD_QUERY_SERVICE)) {
+		
+		addCustomQueryParams(param_list, lang);
+		createParameter(MAXDOCS_PARAM, param_list, lang);
+		if (!default_index_subcollection.equals("")){
+		    createParameter(INDEX_SUBCOLLECTION_PARAM,param_list, lang);
+		}
+		if (!default_index_language.equals("")){
+		    createParameter(INDEX_LANGUAGE_PARAM,param_list, lang); 
+		    }
+		// create a multi param for the fields etc
+		// text box, field
+		Element multiparam = null;
+		Element param=null;
+		multiparam = GSXML.createParameterDescription(this.doc, SIMPLE_FIELD_PARAM, "", GSXML.PARAM_TYPE_MULTI, null, null, null);
+		multiparam.setAttribute("occurs", "4");
+		param_list.appendChild(multiparam);
+		
+		// the components
+		
+		createParameter(FIELD_QUERY_PARAM, multiparam,  lang);
+		createParameter(FIELD_FIELD_PARAM, multiparam,  lang);
+				
+	    } else { 
+		createParameter(LEVEL_PARAM, param_list,  lang);
+		createParameter(RANK_PARAM, param_list, lang);
+		createParameter(MAXDOCS_PARAM, param_list,  lang);
+		if (!default_index_subcollection.equals("")){
+		    createParameter(INDEX_SUBCOLLECTION_PARAM,param_list, lang);
+		}
+		if (!default_index_language.equals("")){
+		    createParameter(INDEX_LANGUAGE_PARAM,param_list, lang); 
+		}
+		
+		// create a multi param for the fields etc
+		// text box, stem, case, field
+		
+		Element multiparam = null;
+		Element param=null;
+		
+		multiparam = GSXML.createParameterDescription(this.doc, ADVANCED_FIELD_PARAM, "", GSXML.PARAM_TYPE_MULTI, null, null, null);
+		multiparam.setAttribute("occurs", "4");
+		param_list.appendChild(multiparam);
+		
+		createParameter(FIELD_COMBINE_PARAM, multiparam, lang);
+		createParameter(FIELD_QUERY_PARAM, multiparam, lang);
+		if (this.does_case) {
+		    createParameter(FIELD_CASE_PARAM, multiparam, lang);
+		}
+		if (this.does_stem) {
+		    createParameter(FIELD_STEM_PARAM, multiparam, lang);
+		}
+		if (this.does_accent) {
+		    createParameter(FIELD_ACCENT_PARAM, multiparam, lang);
+		}
+		createParameter(FIELD_FIELD_PARAM, multiparam, lang);    
+		
+	    } 
+	}
+	return service;
+	
+    }
+    
+    /** add in the level params to TextQuery */
+    protected void addCustomQueryParams(Element param_list, String lang) 
+    {
+	createParameter(LEVEL_PARAM, param_list, lang);
+	super.addCustomQueryParams(param_list, lang);
+    }
+
+    /** create a param and add to the list */
+    protected void createParameter(String name, Element param_list, String lang) 
+    {
+	Element param = null;
+	if (name.equals(LEVEL_PARAM)) {
+	    ArrayList level_ids = new ArrayList();
+	    ArrayList level_names = new ArrayList();
+	    getLevelData(level_ids, level_names, lang);
+	    if (level_ids.size()>1) {
+		// the first one is the default
+		param = GSXML.createParameterDescription2(this.doc, LEVEL_PARAM, getTextString("param."+LEVEL_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, (String)level_ids.get(0), level_ids, level_names);
+	    } else {
+		// we need to set the level, but hidden, in case there is an invalid level saved
+		param = GSXML.createParameterDescription(this.doc, LEVEL_PARAM, "", GSXML.PARAM_TYPE_INVISIBLE, (String)level_ids.get(0), null, null);
+	    }
+	} else if (name.equals(RANK_PARAM)) {
+	    String [] vals1 = {RANK_PARAM_RANK, RANK_PARAM_NONE };
+	    String [] vals1_texts = { getTextString("param."+RANK_PARAM+"."+RANK_PARAM_RANK, lang), getTextString("param."+RANK_PARAM+"."+RANK_PARAM_NONE, lang)};
+	    
+	    param = GSXML.createParameterDescription(this.doc, RANK_PARAM, getTextString("param."+RANK_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, RANK_PARAM_RANK, vals1, vals1_texts );
+	    
+	} else if (name.equals(FIELD_QUERY_PARAM)) {
+	    param = GSXML.createParameterDescription(this.doc, FIELD_QUERY_PARAM, getTextString("param."+FIELD_QUERY_PARAM, lang), GSXML.PARAM_TYPE_STRING, null, null, null);
+	    
+	    
+	} else if (name.equals(FIELD_CASE_PARAM) || name.equals(FIELD_STEM_PARAM) || name.equals(FIELD_ACCENT_PARAM)) {
+	    String[] bool_ops = {"0", "1"};
+	    String[] bool_texts = {getTextString("param.boolean.off", lang, "AbstractSearch"),getTextString("param.boolean.on", lang, "AbstractSearch")}; 
+	    param = GSXML.createParameterDescription(this.doc, name, getTextString("param."+name, lang), GSXML.PARAM_TYPE_BOOLEAN, BOOLEAN_PARAM_ON, bool_ops, bool_texts);
+	    
+	} else if (name.equals(FIELD_FIELD_PARAM)) {
+	    ArrayList fields = new ArrayList();
+	    ArrayList field_names = new ArrayList();
+	    getIndexData(fields, field_names, lang);
+	    // the field list -  read from config file
+	    param = GSXML.createParameterDescription2(this.doc, name, getTextString("param."+name, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, (String)fields.get(0), fields, field_names );
+	    
+	} else if (name.equals(FIELD_COMBINE_PARAM)) {
+	    
+	    String []vals = {FIELD_COMBINE_PARAM_AND, FIELD_COMBINE_PARAM_OR, FIELD_COMBINE_PARAM_NOT};
+	    String []val_texts = {getTextString("param."+FIELD_COMBINE_PARAM+"."+FIELD_COMBINE_PARAM_AND, lang), getTextString("param."+FIELD_COMBINE_PARAM+"."+FIELD_COMBINE_PARAM_OR, lang), getTextString("param."+FIELD_COMBINE_PARAM+"."+FIELD_COMBINE_PARAM_NOT, lang)}; 
+		
+	    
+	    param = GSXML.createParameterDescription(this.doc, FIELD_COMBINE_PARAM, "", GSXML.PARAM_TYPE_ENUM_SINGLE, FIELD_COMBINE_PARAM_AND, vals, val_texts);
+	    param.setAttribute(GSXML.PARAM_IGNORE_POS_ATT, "0");
+	}
+
+	if (param != null) {
+	    param_list.appendChild(param);
+	} else {
+	    super.createParameter(name, param_list, lang);
+	}
+    }
+    
+    // should cache some of this
+    protected void getLevelData(ArrayList level_ids, ArrayList level_names, String lang) 
+    {
+	Element level_list = (Element)GSXML.getChildByTagName(this.config_info, LEVEL_ELEM+GSXML.LIST_MODIFIER);
+	NodeList levels = level_list.getElementsByTagName(LEVEL_ELEM);
+	for (int i=0; i<levels.getLength(); i++) {
+	    Element level = (Element)levels.item(i);
+	    String shortname = level.getAttribute(GSXML.SHORTNAME_ATT);
+	    if (shortname.equals("")) {
+		continue;
+	    }
+	    level_ids.add(shortname);
+	    String display_name = GSXML.getDisplayText(level, GSXML.DISPLAY_TEXT_NAME, lang, "en");
+	    if (display_name.equals("")) {
+		// we'll use the name, and the dictionary
+		display_name = level.getAttribute(GSXML.NAME_ATT);
+		if (display_name.equals("")) {
+		    display_name = shortname;
+		} else {
+		    display_name = getTextString("level."+display_name, lang);
+		}
+	    }
+	    level_names.add(display_name);
+	}
+    }
+
+    // the following three functions are needed so the base class can 
+    // call the process+SERVICE_NAME methods
+    /** process a text query */
+    protected Element processTextQuery(Element request) {
+	return processAnyQuery(request, TEXT_QUERY);
+    }
+
+    /** process a field query */    
+    protected Element processFieldQuery(Element request) {
+	return processAnyQuery(request, SIMPLE_QUERY);
+    }
+
+    /** process an advanced field query */
+    protected Element processAdvancedFieldQuery(Element request) {
+	return processAnyQuery(request, ADVANCED_QUERY);
+    }
+    
+    /** process a  query */
+    protected Element processAnyQuery(Element request, int query_type)
+    {
+
+	String service_name=null;
+	String empty_query_test_param=null;
+	// set up the type specific bits
+	switch (query_type) {
+	case TEXT_QUERY:
+	    service_name = TEXT_QUERY_SERVICE; 
+	    empty_query_test_param = QUERY_PARAM;
+	    break;
+	case SIMPLE_QUERY:
+	    service_name = FIELD_QUERY_SERVICE;
+	    empty_query_test_param = FIELD_QUERY_PARAM;
+	    break;
+	case ADVANCED_QUERY:
+	    service_name = ADVANCED_FIELD_QUERY_SERVICE;
+	    empty_query_test_param = FIELD_QUERY_PARAM;
+	    break;
+	default:
+	    // should never get here
+	    logger.error("wrong query type!!");
+	    return null;
+	}
+	
+	// Create a new (empty) result message
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.setAttribute(GSXML.FROM_ATT, service_name);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+	
+	// Get the parameters of the request
+	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (param_list == null) {
+	    logger.error("TextQuery request had no paramList.");
+	    return result;  // Return the empty result
+	}
+
+	// Process the request parameters
+	HashMap params = GSXML.extractParams(param_list, false);
+
+	// Make sure a query has been specified
+	String query = (String) params.get(empty_query_test_param);
+	if (query == null || query.equals("")) {
+	    return result;  // Return the empty result
+	}
+
+	// If a field hasn't been specified, use the default - for textQuery
+	String field = (String) params.get(INDEX_PARAM); 
+	if (field == null) {
+	    field = default_index;
+	}
+	
+	// set up the appropriate query system
+	if (!setUpQueryer(params)) {
+	    return result;
+	}
+	
+	// if field search, create the query string
+	switch (query_type) {
+	case TEXT_QUERY:
+	    query = addFieldInfo(query, field);
+	    break;
+	case SIMPLE_QUERY:
+	    query = parseFieldQueryParams(params);
+	    break;
+	case ADVANCED_QUERY:
+	    query = parseAdvancedFieldQueryParams(params);
+	    break;
+	}
+	
+	// run the query
+	Object query_result = runQuery(query);
+	
+	// build up the response
+	
+	// Create a metadata list to store information about the query results
+	// should we be using metadataList? or something else?
+	Element metadata_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER); 
+	result.appendChild(metadata_list);
+
+	// Add a metadata element specifying the number of matching documents
+	long totalDocs = numDocsMatched(query_result);
+	
+	GSXML.addMetadata(this.doc, metadata_list, "numDocsMatched", ""+totalDocs);
+
+	// Create a document list to store the matching documents, and add them
+	String [] docs = getDocIDs(query_result);
+	String [] doc_ranks = getDocRanks(query_result);
+
+	// add a metadata item to specify docs returned
+	int docs_returned = docs.length;
+	if (does_paging) {
+	    String maxdocs_str = (String)params.get(MAXDOCS_PARAM);
+	    if (maxdocs_str != null) {
+		int maxdocs = Integer.parseInt(maxdocs_str);
+		docs_returned = (maxdocs < (int)totalDocs ? maxdocs : (int)totalDocs);
+	    }
+	}
+	GSXML.addMetadata(this.doc, metadata_list, "numDocsReturned", ""+docs_returned);
+
+	// add a metadata item to specify what actual query was done - eg if stuff was stripped out etc. and then we can use the query later, cos we don't know which parameter was the query
+	GSXML.addMetadata(this.doc, metadata_list, "query", query);
+	if (docs.length>0) {
+	    Element document_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	    result.appendChild(document_list);
+	    for (int d = 0; d < docs.length; d++) {
+		String doc_id = internalNum2OID(docs[d]);
+		Element doc_node = createDocNode(doc_id, doc_ranks[d]);
+		document_list.appendChild(doc_node);
+	    }
+	}
+
+	// Create a term list to store the term information, and add it
+	Element term_list = this.doc.createElement(GSXML.TERM_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(term_list);
+	addTermInfo(term_list, params, query_result);
+
+	return result;
+    }
+
+    /** methods to handle actually doing the query */
+    /** do any initialisation of the query object */
+    abstract protected boolean setUpQueryer(HashMap params);
+    /** do the query */
+    abstract protected Object runQuery(String query);
+    /** get the total number of docs that match */
+    abstract protected long numDocsMatched(Object query_result);
+    /** get the list of doc ids */
+    abstract protected String [] getDocIDs(Object query_result);
+    /** get the list of doc ranks */
+    abstract protected String [] getDocRanks(Object query_result);
+    /** add in term info if available */
+    abstract protected boolean addTermInfo(Element term_list, HashMap params,
+					   Object query_result);
+    
+    /** combines all the field params into a single query
+     * - for simple field query */
+    /** We assume the combination (AND/OR) is done by the match param */
+    protected String parseFieldQueryParams(HashMap params) {
+
+	StringBuffer final_query = new StringBuffer(256);
+	String text_line = (String)params.get(FIELD_QUERY_PARAM);
+	String[] texts = text_line.split(",", -1);
+	String field_line = (String)params.get(FIELD_FIELD_PARAM);
+	String[] fields = field_line.split(",", -1);
+	
+	for (int i=0; i<texts.length; i++) {
+	    String q = texts[i].trim();
+	    if (!q.equals("")) {
+		final_query.append(" "+addFieldInfo(q, fields[i]));
+	    }
+	}
+
+	return final_query.toString();
+    }
+
+    abstract protected String addFieldInfo(String query, String field);
+    
+    /** combines all the field params into a single query
+     * - for advanced field query */   
+    protected String parseAdvancedFieldQueryParams(HashMap params) {
+
+	StringBuffer final_query = new StringBuffer(256);
+	String text_line = (String)params.get(FIELD_QUERY_PARAM);
+	String[] texts = text_line.split(",", -1);
+	String field_line = (String)params.get(FIELD_FIELD_PARAM);
+	String[] fields = field_line.split(",", -1);
+	String [] cases = null;
+	String [] stems = null;
+	String [] accents = null;
+	if (does_case) {
+	    String case_line = (String)params.get(FIELD_CASE_PARAM);
+	    cases = case_line.split(",", -1);
+	}
+	if (does_stem) {
+	    String stem_line = (String)params.get(FIELD_STEM_PARAM);
+	    stems = stem_line.split(",", -1);
+	}
+	if (does_accent) {
+	    String accent_line = (String)params.get(FIELD_ACCENT_PARAM);
+	    accents = accent_line.split(",", -1);
+	}
+	String combine_line = (String)params.get(FIELD_COMBINE_PARAM);
+	String [] combines = combine_line.split(",", -1);
+	String combine = "";
+	for (int i=0; i<texts.length; i++) {
+	    if (i==0) {// assume first one is blank
+		combine = "";
+	    } else {
+		String x = combines[i]; 
+		if (x.equals(FIELD_COMBINE_PARAM_AND)) {
+		    combine = AND_OPERATOR;
+		} else if (x.equals(FIELD_COMBINE_PARAM_OR)) {
+		    combine = OR_OPERATOR;
+		} else if (x.equals(FIELD_COMBINE_PARAM_NOT)) {
+		    combine = NOT_OPERATOR;
+		} 
+		
+	    }
+
+	    String q = texts[i].trim();
+	    boolean modified = false;
+	    if (!q.equals("")) {
+		String c = null;
+		String s = null;
+		String a = null;
+		if (does_case) {
+		    modified = true;
+		    c = cases[i];
+		}
+		if (does_stem) {
+		    modified = true;
+		    s = stems[i];
+		}
+		if (does_accent) {
+		    modified = true;
+		    a = accents[i];
+		}
+		if (modified) {
+		    q = addStemOptions(q, s, c, a);
+		}
+		addQueryElem(final_query, q, fields[i], combine);
+	    }
+	}
+	return final_query.toString();
+    }
+    
+    abstract protected void addQueryElem(StringBuffer final_query, 
+					 String query, String field, 
+					 String combine);
+    abstract protected String addStemOptions(String query, String stem,
+					     String casef, String accent);
+    
+}
+
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/AbstractGS2Search.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/AbstractGS2Search.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/AbstractGS2Search.java	(revision 14125)
@@ -0,0 +1,367 @@
+/*
+ *    GS2MGSearch.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *   the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.service;
+
+
+// Greenstone classes
+import org.greenstone.mg.*;
+import org.greenstone.gsdl3.util.*;
+
+// XML classes
+import org.w3c.dom.Document;
+import org.w3c.dom.Element; 
+import org.w3c.dom.NodeList;
+
+// java
+import java.util.Vector;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.Iterator;
+import java.io.File;
+
+import org.apache.log4j.*;
+
+public abstract class AbstractGS2Search 
+    extends AbstractSearch 
+{
+
+    protected static final String EQUIV_TERM_ELEM = "equivTerm";
+
+    protected static final String STEM_ATT = "stem";
+    protected static final String NUM_DOCS_MATCH_ATT = "numDocsMatch";
+    protected static final String FREQ_ATT = "freq";
+
+    // Elements used in the config file that are specific to this class
+    protected static final String DEFAULT_INDEX_ELEM = "defaultIndex";
+    protected static final String INDEX_STEM_ELEM = "indexStem";
+    protected static final String INDEX_ELEM = "index";
+    protected static final String DEFAULT_INDEX_SUBCOLLECTION_ELEM = "defaultIndexSubcollection";
+    protected static final String DEFAULT_INDEX_LANGUAGE_ELEM = "defaultIndexLanguage";
+    protected static final String INDEX_SUBCOLLECTION_ELEM = "indexSubcollection";
+    protected static final String INDEX_LANGUAGE_ELEM = "indexLanguage";
+   
+
+    // Some indexing options
+    protected static final String STEMINDEX_OPTION = "stemIndexes";
+    protected static final String MAXNUMERIC_OPTION = "maxnumeric";
+
+    /** the stem used for the index files */
+    protected String index_stem = null;
+
+    // stem indexes available
+    protected boolean does_case=true;
+    protected boolean does_stem=true;
+    protected boolean does_accent=false;
+
+    // maxnumeric - 
+    protected int maxnumeric = 4;
+
+    protected GDBMWrapper gdbm_src = null;
+
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.GS2MGSearch.class.getName());
+
+
+    /** constructor */
+    public AbstractGS2Search()
+    {
+	this.gdbm_src = new GDBMWrapper();
+    }
+    public void cleanUp() {
+	super.cleanUp();
+	this.gdbm_src.closeDatabase();
+    }
+
+    /** configure this service */
+    public boolean configure(Element info, Element extra_info)
+    {
+	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+
+	// do we support any of the extended features?
+	does_chunking = true;
+
+	// Get the default index out of <defaultIndex> (buildConfig.xml)
+	Element def = (Element) GSXML.getChildByTagName(info, DEFAULT_INDEX_ELEM);
+	if (def != null) {
+	    this.default_index = def.getAttribute(GSXML.SHORTNAME_ATT);
+	} // otherwise will be "", and the first one will be the default
+        
+        //get the default indexSubcollection out of <defaultIndexSubcollection> (buildConfig.xml)
+        Element defSub = (Element) GSXML.getChildByTagName(info, DEFAULT_INDEX_SUBCOLLECTION_ELEM); 
+	if (defSub != null) {
+	    this.default_index_subcollection = defSub.getAttribute(GSXML.SHORTNAME_ATT);
+	} 
+
+	//get the default indexLanguage out of <defaultIndexLanguage> (buildConfig.xml)
+        Element defLang = (Element) GSXML.getChildByTagName(info, DEFAULT_INDEX_LANGUAGE_ELEM); 
+	if (defLang != null) {
+	    this.default_index_language = defLang.getAttribute(GSXML.SHORTNAME_ATT);
+	} //concate defaultIndex + defaultIndexSubcollection + defaultIndexLanguage
+     
+
+	// the index stem is either the collection name or is specified in the config file
+	Element index_stem_elem = (Element) GSXML.getChildByTagName(info, INDEX_STEM_ELEM);
+	if (index_stem_elem != null) {
+	    this.index_stem = index_stem_elem.getAttribute(GSXML.NAME_ATT);
+	}
+	if (this.index_stem == null || this.index_stem.equals("")) {
+	    logger.warn("indexStem element not found, stem will default to collection name");
+	    this.index_stem = this.cluster_name;
+	}
+	
+	// get index options
+	Element index_option_list = (Element) GSXML.getChildByTagName(info, GSXML.INDEX_OPTION_ELEM + GSXML.LIST_MODIFIER);
+	if (index_option_list != null) {
+	    NodeList options = index_option_list.getElementsByTagName(GSXML.INDEX_OPTION_ELEM);
+	    for (int i=0; i<options.getLength(); i++) {
+		Element opt = (Element)options.item(i);
+		String name = opt.getAttribute(GSXML.NAME_ATT);
+		String value = opt.getAttribute(GSXML.VALUE_ATT);
+		if (name.equals(MAXNUMERIC_OPTION)) {
+		    int maxnum = Integer.parseInt(value);
+		    if (4 <= maxnum && maxnum < 512) {
+			maxnumeric = maxnum;
+		    }
+		}
+		else if (name.equals(STEMINDEX_OPTION)) {
+		    int stemindex = Integer.parseInt(value);
+		    // stem and case are true by default, accent folding false by default
+		    if ((stemindex & 1) == 0) {
+			does_case = false;
+		    }
+		    if ((stemindex & 2) == 0) {
+			does_stem = false;
+		    }
+		    if ((stemindex & 4) != 0) {
+			does_accent = true;
+		    }
+		}
+	    }
+	}
+
+	// get display info from extra info
+	if (extra_info !=null) {
+	    Document owner = info.getOwnerDocument();
+	    // so far we have index specific display elements, and global format elements 
+	    NodeList indexes = info.getElementsByTagName(GSXML.INDEX_ELEM);
+	    Element config_search = (Element)GSXML.getChildByTagName(extra_info, GSXML.SEARCH_ELEM);
+	    
+	    for (int i=0; i<indexes.getLength();i++) {
+		Element ind = (Element)indexes.item(i);
+		String name = ind.getAttribute(GSXML.NAME_ATT);
+		Element node_extra = GSXML.getNamedElement(config_search,
+							   GSXML.INDEX_ELEM,
+							   GSXML.NAME_ATT,
+							   name);
+		if (node_extra == null) {
+		    logger.error("haven't found extra info for index named "+name);
+		    continue;
+		}
+		
+		// get the display elements if any - displayName
+		NodeList display_names = node_extra.getElementsByTagName(GSXML.DISPLAY_TEXT_ELEM);
+		if (display_names !=null) {
+		    for (int j=0; j<display_names.getLength(); j++) {
+			Element e = (Element)display_names.item(j);
+			ind.appendChild(owner.importNode(e, true));
+		    }
+		}
+	    } // for each index
+	}
+    	// Open GDBM database for querying
+	String gdbm_db_file = GSFile.GDBMDatabaseFile(this.site_home, this.cluster_name, this.index_stem);
+	if (!this.gdbm_src.openDatabase(gdbm_db_file, GDBMWrapper.READER)) {
+	    logger.error(" Could not open GDBM database!");
+	    return false;
+	}
+	return true;
+    }
+
+    protected void getIndexData(ArrayList index_ids, ArrayList index_names, String lang) {
+	// the index info -
+	Element index_list = (Element)GSXML.getChildByTagName(this.config_info, INDEX_ELEM+GSXML.LIST_MODIFIER);
+	NodeList indexes = index_list.getElementsByTagName(INDEX_ELEM);
+	int len = indexes.getLength();
+	// now add even if there is only one
+	for (int i=0; i<len; i++) {
+	    Element index = (Element)indexes.item(i);
+	    String shortname = index.getAttribute(GSXML.SHORTNAME_ATT);
+	    if (shortname.equals("")) {
+		continue;
+	    }
+	    index_ids.add(shortname);
+	    String display_name = GSXML.getDisplayText(index, GSXML.DISPLAY_TEXT_NAME, lang, "en");
+	    if (display_name.equals("")) {
+		display_name = index.getAttribute(GSXML.NAME_ATT);
+		if (display_name.equals("")) {
+		    display_name = shortname;
+		}
+	    }
+	    index_names.add(display_name);
+	}	
+    }
+
+    protected void getIndexSubcollectionData(ArrayList index_sub_ids, ArrayList index_sub_names, String lang){
+	// the index info -
+	Element index_sub_list = (Element)GSXML.getChildByTagName(this.config_info, INDEX_SUBCOLLECTION_ELEM+GSXML.LIST_MODIFIER);
+	NodeList index_subs = index_sub_list.getElementsByTagName(INDEX_SUBCOLLECTION_ELEM);
+	int len = index_subs.getLength();
+	// now add even if there is only one
+	for (int i=0; i<len; i++) {
+	    Element indexsub = (Element)index_subs.item(i);
+	    String shortname = indexsub.getAttribute(GSXML.SHORTNAME_ATT);
+	    if (shortname.equals("")) {
+		continue;
+	    }
+	    index_sub_ids.add(shortname);
+	    String display_name = GSXML.getDisplayText(indexsub, GSXML.DISPLAY_TEXT_NAME, lang, "en");
+	    if (display_name.equals("")) {
+		display_name = indexsub.getAttribute(GSXML.NAME_ATT);
+		if (display_name.equals("")) {
+		    display_name = shortname;
+		}
+	    }
+	    index_sub_names.add(display_name);
+	}		 
+     }
+      
+    protected void getIndexLanguageData(ArrayList index_lang_ids, ArrayList index_lang_names, String lang){
+	// the index info -
+	Element index_lang_list = (Element)GSXML.getChildByTagName(this.config_info, INDEX_LANGUAGE_ELEM+GSXML.LIST_MODIFIER);
+	NodeList index_langs = index_lang_list.getElementsByTagName(INDEX_LANGUAGE_ELEM);
+	int len = index_langs.getLength();
+	// now add even if there is only one
+	for (int i=0; i<len; i++) {
+	    Element indexlang = (Element)index_langs.item(i);
+	    String shortname = indexlang.getAttribute(GSXML.SHORTNAME_ATT);
+	    if (shortname.equals("")) {
+		continue;
+	    }
+	    index_lang_ids.add(shortname);
+	    String display_name = GSXML.getDisplayText(indexlang, GSXML.DISPLAY_TEXT_NAME, lang, "en");
+	    if (display_name.equals("")) {
+		display_name = indexlang.getAttribute(GSXML.NAME_ATT);
+		if (display_name.equals("")) {
+		    display_name = shortname;
+		}
+	    }
+	    index_lang_names.add(display_name);
+	}	
+	
+
+    }
+
+
+    protected void addCustomQueryParams(Element param_list, String lang) 
+    {
+	if (this.does_case){
+	    createParameter(CASE_PARAM, param_list, lang);
+	}
+	if (this.does_stem){
+	    createParameter(STEM_PARAM, param_list, lang);
+	}
+	if (this.does_accent){
+	    createParameter(ACCENT_PARAM, param_list, lang);
+	}
+	createParameter(MATCH_PARAM, param_list, lang);
+    }
+
+
+
+    /** returns the document type of the doc that the specified node 
+	belongs to. should be one of 
+	GSXML.DOC_TYPE_SIMPLE, 
+	GSXML.DOC_TYPE_PAGED, 
+	GSXML.DOC_TYPE_HIERARCHY
+    */
+    protected String getDocType(String node_id){
+	DBInfo info = this.gdbm_src.getInfo(node_id);
+	if (info == null) {
+	    return GSXML.DOC_TYPE_SIMPLE;
+	}
+	String doc_type = info.getInfo("doctype");
+	if (!doc_type.equals("")&&!doc_type.equals("doc")) {
+	    return doc_type;
+	}
+
+	String top_id = OID.getTop(node_id);
+	boolean is_top = (top_id.equals(node_id) ? true : false);
+	
+	String children = info.getInfo("contains");
+	boolean is_leaf = (children.equals("") ? true : false);
+
+	if (is_top && is_leaf) { // a single section document
+	    return GSXML.DOC_TYPE_SIMPLE;
+	}
+
+	// now we just check the top node
+	if (!is_top) { // we need to look at the top info
+	    info = this.gdbm_src.getInfo(top_id);
+	}
+	if (info == null) {
+	    return GSXML.DOC_TYPE_HIERARCHY;
+	}
+ 
+	String childtype = info.getInfo("childtype");
+	if (childtype.equals("Paged")) {
+	    return GSXML.DOC_TYPE_PAGED;
+	}
+	return GSXML.DOC_TYPE_HIERARCHY;
+
+    }
+    
+    /** returns true if the node has child nodes */
+    protected boolean hasChildren(String node_id){
+	DBInfo info = this.gdbm_src.getInfo(node_id);
+	if (info == null) {
+	    return false;
+	}
+	String contains = info.getInfo("contains");
+	if (contains.equals("")) {
+	    return false;
+	}
+	return true;
+    }
+    
+    /** returns true if the node has a parent */
+    protected boolean hasParent(String node_id){
+	String parent = OID.getParent(node_id);
+	if (parent.equals(node_id)) {
+	    return false;
+	}
+	return true;
+    }
+    
+   /** convert MG internal id to Greenstone oid */
+    protected String internalNum2OID(long docnum)
+    {
+	return this.gdbm_src.docnum2OID(docnum);
+	
+    }
+    protected String internalNum2OID(String docnum)
+    {
+	return this.gdbm_src.docnum2OID(docnum);
+	
+    }
+
+}
+
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/AbstractSearch.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/AbstractSearch.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/AbstractSearch.java	(revision 14125)
@@ -0,0 +1,389 @@
+/*
+ *    AbstractSearch.java
+ *    Copyright (C) 2005 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.service;
+
+// Greenstone classes
+import org.greenstone.gsdl3.util.GSXML;
+import org.greenstone.gsdl3.util.GSPath;
+
+// XML classes
+import org.w3c.dom.Document;
+import org.w3c.dom.Element; 
+import org.w3c.dom.NodeList;
+
+// java classes
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.apache.log4j.*;
+
+/** Partially implements a generic search service
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ */
+
+public abstract class AbstractSearch
+    extends ServiceRack 
+{
+
+   static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.AbstractSearch.class.getName());
+
+    
+    // the search service
+    protected static final String TEXT_QUERY_SERVICE = "TextQuery";
+
+    // compulsory params
+    protected static final String INDEX_PARAM = "index";
+    protected static final String QUERY_PARAM = "query";
+
+    // optional standard params - some of these have to be implemented
+    protected static final String INDEX_SUBCOLLECTION_PARAM = "indexSubcollection";
+    protected static final String INDEX_LANGUAGE_PARAM = "indexLanguage";
+    protected static final String MAXDOCS_PARAM = "maxDocs";
+    protected static final String HITS_PER_PAGE_PARAM = "hitsPerPage";
+    protected static final String START_PAGE_PARAM = "startPage";
+
+    protected static final String INDEX_SUBCOLLECTION_ELEM = "indexSubcollection";
+    protected static final String INDEX_LANGUAGE_ELEM = "indexLanguage";
+   
+
+    // some other common params that may be used
+    protected static final String CASE_PARAM = "case";
+    protected static final String STEM_PARAM = "stem";
+    protected static final String ACCENT_PARAM="accent";
+
+    protected static final String BOOLEAN_PARAM_ON = "1";
+    protected static final String BOOLEAN_PARAM_OFF = "0";
+    protected static final String MATCH_PARAM = "matchMode";
+    protected static final String MATCH_PARAM_ALL = "all";
+    protected static final String MATCH_PARAM_SOME = "some";
+
+    /** can more than one index be searched at the smae time? */
+    protected boolean does_multi_index_search = false;
+    /** does this service support paging of results? */
+    protected boolean does_paging = false;
+    /** does this service support asking for a subset of results? */
+    protected boolean does_chunking = false;
+    /** the default document type - use if all documents are the same type
+     */
+    protected String default_document_type = null;
+    /** the default index, or comma separated list if more than one is 
+     * the default (with start and end commas, eg ,TI,SU,). 
+     * Should be set by configure()
+     */
+    protected String default_index = "";
+
+    protected String default_index_subcollection = "";
+
+    protected String default_index_language = "";
+
+    public AbstractSearch()
+    {
+    }
+
+    /** sets up the short service info for TextQuery. If other services 
+     * will be provided, should be added in the subclass configure
+     * also looks for search format info, and document format info
+     */
+    public boolean configure(Element info, Element extra_info)
+    {
+	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+
+	logger.info("Configuring AbstractSearch...");
+	
+	this.config_info = info;
+
+	// set up short_service_info_ - for now just has id and type. the name (lang dependent) will be added in if the list is requested.
+	Element tq_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	tq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
+	tq_service.setAttribute(GSXML.NAME_ATT, TEXT_QUERY_SERVICE);
+	this.short_service_info.appendChild(tq_service);
+
+	// add some format info to service map if there is any - look in extra info
+	// first look in buildConfig
+	Element format = (Element)GSXML.getChildByTagName(info, GSXML.FORMAT_ELEM);
+
+	if (format==null) {
+	    String path = GSPath.appendLink(GSXML.SEARCH_ELEM, GSXML.FORMAT_ELEM);
+	    format = (Element) GSXML.getNodeByPath(extra_info, path);
+	}
+	//Element format = (Element) GSXML.getChildByTagName(info, GSXML.FORMAT_ELEM);
+	if (format != null) {
+	    this.format_info_map.put(TEXT_QUERY_SERVICE, this.doc.importNode(format, true));
+	}
+	
+	// look for document display format - for documentType
+	String path = GSPath.appendLink(GSXML.DISPLAY_ELEM, GSXML.FORMAT_ELEM);
+	Element display_format = (Element)GSXML.getNodeByPath(extra_info, path);
+	if (display_format != null) {
+	    // check for docType option.
+	    Element doc_type_opt = GSXML.getNamedElement(display_format, "gsf:option", GSXML.NAME_ATT, "documentType");
+	    if (doc_type_opt != null) {
+		String value = doc_type_opt.getAttribute(GSXML.VALUE_ATT);
+		if (!value.equals("")) {
+		    this.default_document_type = value;
+		}
+	    }
+	}
+
+	return true;
+    }
+    
+    /** returns the description of the TextQuery service. If a subclass 
+     * provides other services they need to provides their own descriptions */
+    protected Element getServiceDescription(String service, String lang, String subset) 
+    {
+	if (!service.equals(TEXT_QUERY_SERVICE)) {
+	    return null;
+	}
+
+	Element tq_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	tq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
+	tq_service.setAttribute(GSXML.NAME_ATT, TEXT_QUERY_SERVICE);
+	if (subset==null || subset.equals(GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER)) {
+	    tq_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_NAME, getServiceName(TEXT_QUERY_SERVICE, lang) ));
+	    tq_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_SUBMIT, getServiceSubmit(TEXT_QUERY_SERVICE, lang) ));
+	    tq_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_DESCRIPTION, getServiceDescription(TEXT_QUERY_SERVICE, lang)));
+	}
+	if (subset==null || subset.equals(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER)) {
+	    Element param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	    addCustomQueryParams(param_list, lang);
+	    addStandardQueryParams(param_list, lang);
+	    tq_service.appendChild(param_list);
+	}
+	return tq_service;
+	
+    }
+
+    // perhaps these should be changed to search down the class hierarchy for 
+    // values - do can just put the info in the resource bundle to use it
+    /** returns the default name for the TextQuery service */
+    protected String getServiceName(String service_id, String lang) {
+	return getTextString(service_id+".name", lang);
+    }
+    
+    /** returns the default description for the TextQuery service */
+    protected String getServiceDescription(String service_id, String lang) {
+	return getTextString(service_id+".description", lang);
+    }
+
+    /** returns the default submit button text for the TextQuery service */
+    protected String getServiceSubmit(String service_id, String lang) {
+	return getTextString(service_id+".submit", lang);
+
+    }
+    /** adds the standard query params into the service description */
+    protected void addStandardQueryParams(Element param_list, String lang) 
+    {
+	if (!default_index.equals("")){
+	    createParameter(INDEX_PARAM, param_list, lang);
+	}
+	if (!default_index_subcollection.equals("")){
+	    createParameter(INDEX_SUBCOLLECTION_PARAM,param_list, lang);
+	}
+	if (!default_index_language.equals("")){
+	    createParameter(INDEX_LANGUAGE_PARAM,param_list, lang); 
+	}
+	if (does_chunking) {
+	    createParameter(MAXDOCS_PARAM, param_list, lang);
+	}
+	if (does_paging) {
+	    createParameter(HITS_PER_PAGE_PARAM, param_list, lang);
+	    createParameter(START_PAGE_PARAM, param_list, lang);
+	}
+	createParameter(QUERY_PARAM, param_list, lang);
+    }
+
+    /** adds any service specific query params into the service
+     *	default implementation: add nothing. subclasses may need to 
+     * override this to add in their specific parameters
+     */
+    protected void addCustomQueryParams(Element param_list, String lang) 
+    {
+	// default behaviour, do nothing
+    }
+
+    /** default implementations for the standard parameters plus some 
+     * other common ones 
+     * index, maxDocs, hitsPerPage, startPage, query, case, stem, 
+    */
+    protected void createParameter(String name, Element param_list, String lang) {
+	Element param = null;
+	if (name.equals(QUERY_PARAM)) {
+	    param = GSXML.createParameterDescription(this.doc, QUERY_PARAM, getTextString("param."+QUERY_PARAM, lang), GSXML.PARAM_TYPE_STRING, null, null, null);
+	    param_list.appendChild(param);
+	} else if (name.equals(INDEX_PARAM)) {
+
+	    // should we make these class fields?
+	    ArrayList index_ids = new ArrayList();
+	    ArrayList index_names = new ArrayList();
+	    getIndexData(index_ids, index_names, lang);
+	    String param_type = GSXML.PARAM_TYPE_ENUM_SINGLE;
+	    if (does_multi_index_search) {
+		param_type = GSXML.PARAM_TYPE_ENUM_MULTI;
+	    }
+	    param = GSXML.createParameterDescription2(this.doc, INDEX_PARAM, getTextString("param."+INDEX_PARAM, lang), param_type, this.default_index, index_ids, index_names);
+	    param_list.appendChild(param);
+	}
+        else if (name.equals(INDEX_SUBCOLLECTION_PARAM)){
+	    Element index_sub_list = (Element)GSXML.getChildByTagName(this.config_info, INDEX_SUBCOLLECTION_ELEM+GSXML.LIST_MODIFIER);
+	     if (index_sub_list == null) return;
+	     ArrayList index_sub_ids = new ArrayList();
+	     ArrayList index_sub_names = new ArrayList();
+	    getIndexSubcollectionData(index_sub_ids, index_sub_names, lang);
+	    String param_type = GSXML.PARAM_TYPE_ENUM_SINGLE;
+	    if (does_multi_index_search) {
+		param_type = GSXML.PARAM_TYPE_ENUM_MULTI;
+	    }
+	    param = GSXML.createParameterDescription2(this.doc, INDEX_SUBCOLLECTION_PARAM, getTextString("param."+INDEX_SUBCOLLECTION_PARAM, lang), param_type, this.default_index_subcollection, index_sub_ids, index_sub_names);
+	    param_list.appendChild(param);
+	}
+	else if(name.equals(INDEX_LANGUAGE_PARAM)){
+	    Element index_lang_list = (Element)GSXML.getChildByTagName(this.config_info, INDEX_LANGUAGE_ELEM+GSXML.LIST_MODIFIER);
+            if (index_lang_list == null) return; 
+	    ArrayList index_lang_ids = new ArrayList();
+	    ArrayList index_lang_names = new ArrayList();
+	    getIndexLanguageData(index_lang_ids, index_lang_names, lang);
+	    String param_type = GSXML.PARAM_TYPE_ENUM_SINGLE;
+	    if (does_multi_index_search) {
+		param_type = GSXML.PARAM_TYPE_ENUM_MULTI;
+	    }
+	    param = GSXML.createParameterDescription2(this.doc, INDEX_LANGUAGE_PARAM, getTextString("param."+INDEX_LANGUAGE_PARAM, lang), param_type, this.default_index_language, index_lang_ids, index_lang_names);
+	    param_list.appendChild(param);
+	}
+        else if (name.equals(MAXDOCS_PARAM) || name.equals(HITS_PER_PAGE_PARAM)) {
+	    String default_val = "100";
+	    if (name.equals(HITS_PER_PAGE_PARAM)) {
+		default_val = "10";
+	    }
+	    param = GSXML.createParameterDescription(this.doc, name, getTextString("param."+name, lang), GSXML.PARAM_TYPE_INTEGER, default_val, null, null);
+	    param_list.appendChild(param);
+	} else if (name.equals(CASE_PARAM) || name.equals(STEM_PARAM) || name.equals(ACCENT_PARAM)) {
+	    String[] bool_ops = {"0", "1"};
+	    String[] bool_texts = {getTextString("param.boolean.off", lang),getTextString("param.boolean.on", lang)}; 
+	    param = GSXML.createParameterDescription(this.doc, name, getTextString("param."+name, lang), GSXML.PARAM_TYPE_BOOLEAN, BOOLEAN_PARAM_ON, bool_ops, bool_texts);
+	    param_list.appendChild(param);
+	} else if (name.equals(MATCH_PARAM)) {
+	    String[] vals = {MATCH_PARAM_SOME, MATCH_PARAM_ALL };
+	    String[] val_texts = {getTextString("param."+MATCH_PARAM+"."+MATCH_PARAM_SOME, lang), getTextString("param."+MATCH_PARAM+"."+MATCH_PARAM_ALL, lang)}; 
+	    param = GSXML.createParameterDescription(this.doc, MATCH_PARAM, getTextString("param."+MATCH_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, MATCH_PARAM_SOME, vals, val_texts);
+	    param_list.appendChild(param);
+	} else if (name.equals(START_PAGE_PARAM)) {
+	    // start page - set to 1 for the search page
+	    param = GSXML.createParameterDescription(this.doc, START_PAGE_PARAM, "", GSXML.PARAM_TYPE_INVISIBLE, "1", null, null);
+	    param_list.appendChild(param);
+	}
+	    
+	    
+    }
+    /** create an element to go into the search results list. A node element
+     * has the form
+     * <docNode nodeId='xxx' nodeType='leaf' docType='hierarchy' rank='0.23'/>
+     */
+    protected Element createDocNode(String node_id, String rank) {
+	Element node = this.doc.createElement(GSXML.DOC_NODE_ELEM);
+	node.setAttribute(GSXML.NODE_ID_ATT, node_id);
+	node.setAttribute(GSXML.NODE_RANK_ATT, rank);
+	String doc_type = null;
+	if (default_document_type != null) {
+	    doc_type = default_document_type;
+	} else {
+	    doc_type = getDocType(node_id);
+	}
+	node.setAttribute(GSXML.DOC_TYPE_ATT, doc_type);
+	String node_type = getNodeType(node_id, doc_type);	
+	node.setAttribute(GSXML.NODE_TYPE_ATT, node_type);
+	return node;
+    }
+
+    /** returns the node type of the specified node.
+	should be one of 
+	GSXML.NODE_TYPE_LEAF, 
+	GSXML.NODE_TYPE_INTERNAL, 
+	GSXML.NODE_TYPE_ROOT
+    */
+    protected String getNodeType(String node_id, String doc_type) {
+	if (doc_type.equals(GSXML.DOC_TYPE_SIMPLE)) {
+	    return GSXML.NODE_TYPE_LEAF;
+	}
+
+	if (!hasParent(node_id)) {
+	    return GSXML.NODE_TYPE_ROOT;
+	}
+	if (doc_type.equals(GSXML.DOC_TYPE_PAGED)) {
+	     return GSXML.NODE_TYPE_LEAF;
+	}
+	if (!hasChildren(node_id)) {
+	    return GSXML.NODE_TYPE_LEAF;
+	}
+	return GSXML.NODE_TYPE_INTERNAL;	
+	
+    }
+
+
+    /** returns the document type of the doc that the specified node 
+	belongs to. should be one of 
+	GSXML.DOC_TYPE_SIMPLE, 
+	GSXML.DOC_TYPE_PAGED, 
+	GSXML.DOC_TYPE_HIERARCHY
+	default implementation returns GSXML.DOC_TYPE_SIMPLE, over ride 
+	if documents can be hierarchical
+    */
+    protected String getDocType(String node_id) {
+	return GSXML.DOC_TYPE_SIMPLE;
+    }
+    
+    /** returns true if the node has child nodes 
+     * default implementation returns false, over ride if documents can be 
+     * hierarchical 
+     */
+    protected boolean hasChildren(String node_id) {
+	return false;
+    }
+    /** returns true if the node has a parent 
+     * default implementation returns false, over ride if documents can be 
+     * hierarchical*/
+    protected boolean hasParent(String node_id) {
+	return false;
+    }
+
+    /** do the actual query 
+     * must be implemented by subclass */
+    abstract protected Element processTextQuery(Element request); 
+	
+    /** get the details about the indexes available
+     * must be implemented by subclass
+     * there must be at least one index */
+    abstract protected void getIndexData(ArrayList index_ids, ArrayList index_names, String lang);
+
+    /** get the details about the indexexSubcollections available
+     * might be implemented by subclass
+     */
+    protected void getIndexSubcollectionData(ArrayList index_ids, ArrayList index_names, String lang){}
+    
+    /** get the details about the indexes available
+     * might be implemented by subclass
+     */
+    protected void getIndexLanguageData(ArrayList index_ids, ArrayList index_names, String lang){}
+  
+
+}
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/BerryBasket.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/BerryBasket.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/BerryBasket.java	(revision 14125)
@@ -0,0 +1,625 @@
+/*
+ *    BerryBasket.java
+ *    Copyright (C) 2006 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.service;
+
+import java.sql.Statement;
+import java.util.Hashtable;
+import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import org.greenstone.gsdl3.util.GSXML;
+import org.greenstone.gsdl3.util.GSPath;
+
+import java.net.InetAddress;
+import java.util.Properties;
+import java.util.Date;
+
+import javax.mail.*;
+import javax.mail.internet.*;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.Timer;
+
+import org.apache.log4j.*;
+
+public class BerryBasket
+    extends ServiceRack {
+
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.BerryBasket.class.getName());
+
+    // the services on offer
+    // these strings must match what is found in the properties file
+    protected static final String ADD_ITEM_SERVICE = "AddItem";
+    protected static final String DISPLAY_ITEMS_SERVICE = "DisplayList";
+    protected static final String ITEM_NUM_SERVICE = "ItemNum";
+    protected static final String DELETE_ITEMS_SERVICE = "DeleteItems";
+    protected static final String SEND_MAIL_SERVICE = "SendMail";  
+    protected static final String DELETE_ITEM_SERVICE = "DeleteItem";
+
+    protected static final String ITEM_PARAM = "item";
+    protected static final String delimiter ="|";
+    protected static final int delay = 1800000;
+
+    protected Hashtable userMap = null;
+    protected Hashtable timerMap = null;
+    protected String username="";
+    protected String password="";
+
+    
+    /** constructor */
+    public BerryBasket()
+    {
+	userMap =  new Hashtable();
+        timerMap = new Hashtable();
+    }
+
+    private Hashtable updateDocMap(Element request){
+       
+	String id = request.getAttribute("uid");
+        
+    	if (userMap.containsKey(id)){	
+	    if (timerMap.containsKey(id)){
+		UserTimer timer = (UserTimer)timerMap.get(id);
+                timer.restart();
+	    }    
+	    return (Hashtable) userMap.get(id);
+           }
+	else{
+            UserTimer timer = new UserTimer(delay,id);
+            timerMap.put(id,timer);
+            timer.start();
+            Hashtable newDocs= new Hashtable(); 
+	    userMap.put(id,newDocs);
+            return newDocs;
+	}    
+    }
+
+    
+    /** configure this service */
+    public boolean configure(Element info, Element extra_info)
+    {
+	logger.info("Configuring BerryBasket...");
+	this.config_info = info;
+
+	// set up short_service_info_ - for now just has name and type
+	Element add_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	add_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
+	add_service.setAttribute(GSXML.NAME_ATT, ADD_ITEM_SERVICE);
+	this.short_service_info.appendChild(add_service);
+
+	
+	// set up short_service_info_ - for now just has name and type
+	Element disp_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	disp_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
+	disp_service.setAttribute(GSXML.NAME_ATT, DISPLAY_ITEMS_SERVICE);
+	this.short_service_info.appendChild(disp_service);
+
+	// set up short_service_info_ - for now just has name and type
+	Element num_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	num_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
+	num_service.setAttribute(GSXML.NAME_ATT, ITEM_NUM_SERVICE);
+	this.short_service_info.appendChild(num_service);
+
+       	// set up short_service_info_ - for now just has name and type
+	Element delete_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	delete_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
+	delete_service.setAttribute(GSXML.NAME_ATT, DELETE_ITEMS_SERVICE);
+	this.short_service_info.appendChild(delete_service);
+
+        // set up short_service_info_ - for now just has name and type
+	Element deleteone_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	deleteone_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
+	deleteone_service.setAttribute(GSXML.NAME_ATT, DELETE_ITEM_SERVICE);
+	this.short_service_info.appendChild(deleteone_service);
+
+	// set up short_service_info_ - for now just has name and type
+	Element mail_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	mail_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
+	mail_service.setAttribute(GSXML.NAME_ATT, SEND_MAIL_SERVICE);
+	this.short_service_info.appendChild(mail_service);
+
+
+	return true;
+	
+    }
+
+    /** returns a specific service description */
+    protected Element getServiceDescription(String service_id, String lang, String subset) {
+
+	if (service_id.equals(ADD_ITEM_SERVICE)) {
+	    Element add_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    add_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
+	    add_service.setAttribute(GSXML.NAME_ATT, ADD_ITEM_SERVICE);
+	    return add_service;
+	}
+	if (service_id.equals(DISPLAY_ITEMS_SERVICE)) {
+	    
+	    Element disp_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    disp_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
+	    disp_service.setAttribute(GSXML.NAME_ATT, DISPLAY_ITEMS_SERVICE);
+	    return disp_service;
+	}
+
+	if (service_id.equals(ITEM_NUM_SERVICE)) {
+	    
+	    Element num_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    num_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
+	    num_service.setAttribute(GSXML.NAME_ATT, ITEM_NUM_SERVICE);
+	    return num_service;
+	}
+
+	if (service_id.equals(DELETE_ITEMS_SERVICE)) {
+	    
+	    Element del_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    del_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
+	    del_service.setAttribute(GSXML.NAME_ATT, DELETE_ITEMS_SERVICE);
+	    return del_service;
+	}
+
+	if (service_id.equals(DELETE_ITEM_SERVICE)) {
+	    
+	    Element delone_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    delone_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
+	    delone_service.setAttribute(GSXML.NAME_ATT, DELETE_ITEM_SERVICE);
+	    return delone_service;
+	}
+
+	if (service_id.equals(SEND_MAIL_SERVICE)) {
+	    
+	    Element mail_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    mail_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
+	    mail_service.setAttribute(GSXML.NAME_ATT, SEND_MAIL_SERVICE);
+	    return mail_service;
+	}
+
+	return null;
+    }
+
+    protected Element processAddItem(Element request) {
+        Hashtable docsMap = updateDocMap(request);
+
+	// Create a new (empty) result message
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	
+	// Get the parameters of the request
+	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (param_list == null) {
+	    logger.error("BerryBasket Error: AddItem request had no paramList.");
+	    return result;  // Return the empty result
+	}
+
+	HashMap params = GSXML.extractParams(param_list, false);
+
+	String item = (String)params.get("item");
+	String collection = "";
+	int pos = item.indexOf(":");
+	if (pos != -1) {
+	    collection = item.substring(0,pos);
+	    item = item.substring(pos+1);
+	}
+
+	if (docsMap.containsKey(collection)){
+	    Hashtable items = (Hashtable) docsMap.get(collection);
+            if (!items.containsKey(item)){
+                Item newItem = generateItem(collection,item);
+                items.put(item, newItem);
+                result.appendChild(newItem.wrapIntoElement());
+	    }
+	}
+	else{
+	    Hashtable items = new Hashtable();
+            Item newItem = generateItem(collection,item);
+            items.put(item, newItem);
+            docsMap.put(collection,items);
+	    result.appendChild(newItem.wrapIntoElement());
+	}
+
+	return result;
+    }
+
+    private Item generateItem(String collection, String id){
+     
+	Item item = new Item(collection, id);
+  	String to = GSPath.appendLink(collection, "DocumentMetadataRetrieve");
+	ArrayList tmp = new ArrayList();
+	tmp.add(id);  
+	Element response = getDocumentMetadata(to,"en","dumy", tmp.iterator());
+	Element doc_node = (Element)response.getElementsByTagName(GSXML.DOC_NODE_ELEM).item(0); 
+
+	String node_id = doc_node.getAttribute(GSXML.NODE_ID_ATT);
+	Element metadata_list = (Element)doc_node.getElementsByTagName(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER).item(0);
+
+	//assign title metadata if any
+	Element metadata = GSXML.getNamedElement(metadata_list,"metadata","name","Title");
+	if (metadata != null){
+	    item.title = GSXML.getNodeText(metadata).trim();
+	} 
+	//assign date metadata if any
+	metadata = GSXML.getNamedElement(metadata_list,"metadata","name","Date");
+	if (metadata != null){
+	    item.date = GSXML.getNodeText(metadata).trim();
+	}	
+ 	
+	//assign root title metadata if any
+	metadata = GSXML.getNamedElement(metadata_list,"metadata","name","root_Title");
+	if (metadata != null){
+            String rootTitle = GSXML.getNodeText(metadata).trim();
+            if (!rootTitle.equals(item.title)){
+	          item.rootTitle = rootTitle;
+	    }
+	    
+	}
+
+	return item;
+    }
+
+
+    protected Element processDeleteItems(Element request) {
+          Hashtable docsMap = updateDocMap(request);
+	
+	// Create a new (empty) result message
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	
+	// Get the parameters of the request
+	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+        
+        //GSXML.printXMLNode(param_list);
+
+	if (param_list == null) {
+	    logger.error("BerryBasket Error: DeleteItem request had no paramList.");
+	    return result;  // Return the empty result
+	}
+
+	HashMap params = GSXML.extractParams(param_list, false);
+      
+	String param = (String)params.get("items");
+ 
+        if (param == null) return result;     
+
+        String[] items = param.split("\\|");
+ 
+	for (int i=0; i<items.length; i++){
+            String item = items[i];
+	    if (item.trim().length() == 0) continue;
+	  	    String collection = "";
+	    int pos = item.indexOf(":");
+	    if (pos != -1) {
+		collection = item.substring(0,pos);
+		item = item.substring(pos+1);
+	    }
+     
+	    if (docsMap.containsKey(collection)){
+		Hashtable itemMap = (Hashtable) docsMap.get(collection);
+		if (itemMap.containsKey(item)){
+		    itemMap.remove(item);
+		}
+		if (itemMap.size()==0){
+		    docsMap.remove(collection);
+		}
+	    }
+
+	}
+
+	return result;
+    }
+
+     protected Element processDeleteItem(Element request) {
+          Hashtable docsMap = updateDocMap(request);
+	
+	// Create a new (empty) result message
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	
+	// Get the parameters of the request
+	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+        
+        //GSXML.printXMLNode(param_list);
+
+	if (param_list == null) {
+	    logger.error("BerryBasket Error: DeleteItem request had no paramList.");
+	    return result;  // Return the empty result
+	}
+
+	HashMap params = GSXML.extractParams(param_list, false);
+      
+	String param = (String)params.get("item");
+ 
+        if (param == null) return result;     
+
+        String item = param;
+ 
+	String collection = "";
+	int pos = item.indexOf(":");
+	
+	if (pos != -1) {
+	    collection = item.substring(0,pos);
+	    item = item.substring(pos+1);
+	}
+	
+	if (docsMap.containsKey(collection)){
+	    Hashtable itemMap = (Hashtable) docsMap.get(collection);
+	    if (itemMap.containsKey(item)){
+		itemMap.remove(item);
+	    }
+	    if (itemMap.size()==0){
+		docsMap.remove(collection);
+	    }
+	}       
+
+	return result;
+    }
+
+
+    protected Element processItemNum(Element request){
+        // GSXML.printXMLNode(request);
+	Hashtable docsMap = updateDocMap(request);
+
+	// Create a new (empty) result message
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	
+        int size = 0;
+        String ids ="";   
+        Iterator keys = docsMap.keySet().iterator();
+	
+         while(keys.hasNext()){  
+	     Hashtable items = (Hashtable) docsMap.get((String)keys.next());
+             size+=items.size();
+             Iterator values = items.values().iterator();
+             while(values.hasNext()){ 
+		 Item item = (Item)values.next();
+                 result.appendChild(item.wrapIntoElement()); 
+	     }  
+	 }
+
+        Element selement = this.doc.createElement("size");
+	selement.setAttribute("value",size+"");
+        result.appendChild(selement);
+       	
+       	return result;
+    }
+
+    
+    private Element getDocumentMetadata(String to, String lang, String uid, Iterator ids){
+	
+      	// Build a request to obtain some document metadata
+	Element dm_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element dm_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, lang, uid);
+	dm_message.appendChild(dm_request);
+
+	// Create a parameter list to specify the required metadata information
+	HashSet meta_names = new HashSet();
+	meta_names.add("Title"); // the default
+        meta_names.add("root_Title");
+        meta_names.add("Date");
+
+
+       	Element param_list  = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	
+	Element param = null;
+	Iterator i = meta_names.iterator();
+	while (i.hasNext()) {
+	    String name = (String)i.next();
+	    param = this.doc.createElement(GSXML.PARAM_ELEM);
+	    param_list.appendChild(param);
+	    param.setAttribute(GSXML.NAME_ATT, "metadata");
+	    param.setAttribute(GSXML.VALUE_ATT, name);
+	
+	}
+	
+	dm_request.appendChild(param_list);
+	
+	// create the doc node list for the metadata request
+	Element dm_doc_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	dm_request.appendChild(dm_doc_list);
+
+	while (ids.hasNext()){
+	    // Add the documentNode to the list
+	    Element dm_doc_node = this.doc.createElement(GSXML.DOC_NODE_ELEM);
+	    dm_doc_list.appendChild(dm_doc_node);
+	    dm_doc_node.setAttribute(GSXML.NODE_ID_ATT,(String)ids.next());
+	}
+
+	return (Element) this.router.process(dm_message);
+
+    }
+
+
+    protected Element processDisplayList(Element request) {
+	// Create a new (empty) result message
+     	Hashtable docsMap =  updateDocMap(request);
+
+	// Create a new (empty) result message
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	
+        Iterator keys = docsMap.keySet().iterator();
+	
+         while(keys.hasNext()){     
+	     String collection = (String)keys.next(); 
+             Hashtable items = (Hashtable)docsMap.get(collection);
+	     Iterator itemItr = items.values().iterator();
+
+             Element collectionNode = this.doc.createElement("collection");
+             collectionNode.setAttribute("name",collection);
+	     result.appendChild(collectionNode);
+
+	     while(itemItr.hasNext()){  
+                Item item = (Item)itemItr.next();
+	        Element itemElement = this.doc.createElement("item");
+		
+                collectionNode.appendChild(itemElement);
+		itemElement.setAttribute("name", item.docid);
+	        itemElement.setAttribute("collection", item.collection);
+		itemElement.setAttribute("title",item.title);
+		itemElement.setAttribute("date",item.date);
+               	itemElement.setAttribute("root_title",item.rootTitle);                
+ 	     }	     
+	 }
+       
+	return result;
+
+   }
+
+
+    public Element processSendMail(Element request){
+	// Create a new (empty) result message
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	
+	// Get the parameters of the request
+	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+        
+        GSXML.printXMLNode(param_list);
+     
+	if (param_list == null) {
+	    logger.error("BerryBasket Error: SendMail request had no paramList.");
+	    return result;  // Return the empty result
+	}
+
+	HashMap params = GSXML.extractParams(param_list, false);
+      
+	String to = (String)params.get("address");
+        String subject = (String)params.get("subject");
+	String mailhost = (String)params.get("host");
+        String content =  (String)params.get("content");
+        String cc = (String)params.get("cc");
+        String bcc = (String)params.get("bcc");
+        username = (String)params.get("user");
+        password = (String)params.get("password");
+	String mailer = "msgsend";        
+       
+	try {
+	   
+	    Properties props = System.getProperties();
+	    // XXX - could use Session.getTransport() and Transport.connect()
+	    // XXX - assume we're using SMTP
+	    // TODO: need to get Mail server info from the configuration file
+	    if (mailhost != null && mailhost.trim().equals(""))
+		props.put("mail.smtp.host", mailhost);
+	    else{
+		props.put("mail.smtp.host", "webmail.cs.waikato.ac.nz"); 
+	    }
+
+	    // TODO: need to get account info from the configuration file
+            Authenticator auth = new Authenticator(){
+		 protected  PasswordAuthentication  getPasswordAuthentication(){
+		     if (username == null || username.equals("")){
+			 username = "xxxxx";
+                         password = "xxxxx";
+		     }
+		      return new PasswordAuthentication(username,password);
+		  }
+            };
+	
+           Session session = Session.getInstance(props, auth);
+
+	   Message msg = new MimeMessage(session);
+	   msg.setFrom();
+
+	   msg.setRecipients(Message.RecipientType.TO,
+			     InternetAddress.parse(to, false));
+	   if (cc != null)
+	       msg.setRecipients(Message.RecipientType.CC,
+				 InternetAddress.parse(cc, false));
+	    if (bcc != null)
+		msg.setRecipients(Message.RecipientType.BCC,
+				  InternetAddress.parse(bcc, false));
+
+	    msg.setSubject(subject);
+	    
+            msg.setText(content.replaceAll("-------","&"));
+	    msg.setHeader("X-Mailer", mailer);
+	    msg.setSentDate(new Date());
+
+	    // send the thing off
+	    Transport.send(msg);
+	    
+	    logger.info("\nMail was sent successfully.");
+            result.appendChild(this.doc.createTextNode("Mail was sent successfully."));
+	} catch (Exception e) {
+	    e.printStackTrace();
+            result.appendChild(this.doc.createTextNode(e.getMessage()));
+	}
+	
+	return result;
+    }
+
+    protected class Item {
+
+	public String collection;
+	public String docid;
+        public String title="";
+        public String query="";
+        public String date="";
+        public String rootTitle="";
+
+	public Item(String coll, String id) {
+	    this.collection = coll;
+	    this.docid = id;
+        }
+
+        public boolean equals(Object o){
+	    if (! (o instanceof Item)){
+		return false;
+	    }
+	    Item item = (Item)o;
+            String id = collection+":"+docid;
+	    String idin = item.collection+":"+item.docid;
+	    return id.equals(idin);
+
+	}
+
+        public String toString(){
+                
+	    return collection+":"+docid+":"+"["+((!rootTitle.equals(""))?(rootTitle+":"):"")+title+"]";
+	}       
+
+        public Element wrapIntoElement(){
+              Element itemElement = doc.createElement("item");  
+              itemElement.setAttribute("name", docid);
+	      itemElement.setAttribute("collection", collection);
+	      itemElement.setAttribute("title",title);
+	      itemElement.setAttribute("date",date);
+	      itemElement.setAttribute("root_title",rootTitle);
+              return itemElement; 	       
+	}
+    }
+	private class UserTimer extends Timer implements ActionListener{
+            String id="";
+
+            public UserTimer(int delay, String id){
+                super(delay,(ActionListener)null);
+                addActionListener(this);
+		this.id=id;
+	    }
+
+	 
+           public void actionPerformed(ActionEvent e){
+	       userMap.remove(id);            
+               timerMap.remove(id);
+               stop();
+	    }
+
+	}
+    
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/CrossCollectionSearch.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/CrossCollectionSearch.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/CrossCollectionSearch.java	(revision 14125)
@@ -0,0 +1,380 @@
+/*
+ *    CrossCollectionSearch.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.service;
+
+import org.greenstone.gsdl3.util.GSXML;
+import org.greenstone.gsdl3.util.GSPath;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.HashMap;
+
+import org.apache.log4j.*;
+
+/**
+ *
+ * @author <a href="mailto:greenstone@cs.waikato.ac.nz">Katherine Don</a>
+ */
+
+public class CrossCollectionSearch
+    extends ServiceRack {
+
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.CrossCollectionSearch.class.getName());
+    protected static final String QUERY_PARAM = "query";
+    protected static final String COLLECTION_PARAM = "collection";
+
+    // the services on offer - these proxy the actual collection ones
+    protected static final String TEXT_QUERY_SERVICE = "TextQuery";
+    protected static final String ADV_QUERY_SERVICE = "AdvTextQuery";
+    protected static final String DOCUMENT_METADATA_RETRIEVE_SERVICE = "DocumentMetadataRetrieve";
+    
+    protected String [] coll_ids_list = null;
+    protected String [] coll_ids_list_no_all = null;
+    protected String [] coll_names_list = null;
+
+    
+    /** constructor */
+    public CrossCollectionSearch()
+    {
+    }
+
+    public boolean configure(Element info, Element extra_info) 
+    {
+	// any parameters? colls to include??
+	logger.info("Configuring CrossCollectionSearch...");
+	// query service
+	Element ccs_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	ccs_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
+	ccs_service.setAttribute(GSXML.NAME_ATT, TEXT_QUERY_SERVICE);
+	this.short_service_info.appendChild(ccs_service);
+
+	// metadata service
+	Element dmr_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	dmr_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
+	dmr_service.setAttribute(GSXML.NAME_ATT, DOCUMENT_METADATA_RETRIEVE_SERVICE);
+	this.short_service_info.appendChild(dmr_service);
+
+	// get any format info
+	Element format_info = (Element)GSXML.getChildByTagName(info, GSXML.FORMAT_ELEM);
+	if (format_info != null) {
+	    this.format_info_map.put(TEXT_QUERY_SERVICE, this.doc.importNode(format_info, true));
+	} else {
+	    // add in a default format statement
+	    String format_string = "<format xmlns:gsf='http://www.greenstone.org/greenstone3/schema/ConfigFormat' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'><gsf:template match='documentNode'><td><a><xsl:attribute name='href'>?a=d&amp;c=<xsl:value-of select='@collection'/>&amp;d=<xsl:value-of select='@nodeID'/><xsl:if test=\"@nodeType='leaf'\">&amp;sib=1</xsl:if>&amp;dt=<xsl:value-of select='@docType'/>&amp;p.a=q&amp;&amp;p.s="+TEXT_QUERY_SERVICE+"&amp;p.c=";
+	    if (this.cluster_name!=null) {
+		format_string += this.cluster_name;
+	    }
+	    format_string += "</xsl:attribute><gsf:icon/></a></td><td><gsf:metadata name='Title'/> (<xsl:value-of select='@collection'/>) </td></gsf:template></format>";
+	    this.format_info_map.put(TEXT_QUERY_SERVICE, this.doc.importNode(this.converter.getDOM(format_string).getDocumentElement(), true));
+	}
+	return true;
+    }
+
+    protected Element getServiceDescription(String service, String lang, String subset) 
+    {
+	if (service.equals(TEXT_QUERY_SERVICE)) {
+
+	    Element ccs_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    ccs_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
+	    ccs_service.setAttribute(GSXML.NAME_ATT, TEXT_QUERY_SERVICE);
+	    
+	    // display info
+	    if (subset==null || subset.equals(GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER)) {
+		ccs_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_NAME, getTextString(TEXT_QUERY_SERVICE+".name", lang)));
+		ccs_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_SUBMIT, getTextString(TEXT_QUERY_SERVICE+".submit", lang)));
+		ccs_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_DESCRIPTION, getTextString(TEXT_QUERY_SERVICE+".description", lang)));
+	    }
+	    // param info
+	    if (subset==null || subset.equals(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER)) {
+		Element param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+		// collection list
+		if (coll_ids_list ==null ) {
+		    initCollectionList();
+		}
+		Element param = GSXML.createParameterDescription(this.doc, COLLECTION_PARAM, getTextString("param."+COLLECTION_PARAM, lang), GSXML.PARAM_TYPE_ENUM_MULTI, "all", coll_ids_list, coll_names_list);
+		param_list.appendChild(param);
+		// query param
+		param = GSXML.createParameterDescription(this.doc, QUERY_PARAM, getTextString("param."+QUERY_PARAM, lang), GSXML.PARAM_TYPE_STRING, null, null, null);
+		param_list.appendChild(param);
+		ccs_service.appendChild(param_list);
+	    }
+	    
+	    logger.debug("service description="+this.converter.getPrettyString(ccs_service));
+	    return ccs_service;
+	}
+	// these ones are probably never called, but put them here just in case
+	Element service_elem = this.doc.createElement(GSXML.SERVICE_ELEM);
+	service_elem.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
+	service_elem.setAttribute(GSXML.NAME_ATT, service);
+	return service_elem;
+    
+
+    }
+
+    
+    protected Element processTextQuery(Element request) {
+	// Create a new (empty) result message
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.setAttribute(GSXML.FROM_ATT, TEXT_QUERY_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	// Get the parameters of the request
+	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (param_list == null) {
+	    logger.error("TextQuery request had no paramList.");
+	    return result;  // Return the empty result
+	}
+
+	// get the collection list
+	String [] colls_list = coll_ids_list_no_all;
+	Element coll_param = GSXML.getNamedElement(param_list, GSXML.PARAM_ELEM, GSXML.NAME_ATT,  COLLECTION_PARAM);
+	if (coll_param != null) {
+	    String coll_list = GSXML.getValue(coll_param);
+	    if (!coll_list.equals("all") &&  !coll_list.equals("")) {
+		colls_list = coll_list.split(",");
+	    }
+	}
+	
+	Element query_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	// we are sending the same request to each collection - build up the to
+	// attribute for the request
+	StringBuffer to_att = new StringBuffer();
+	for (int i=0; i<colls_list.length; i++) {
+	    if (i>0) {
+		to_att.append(",");
+	    }
+	    to_att.append(GSPath.appendLink(colls_list[i], "TextQuery"));
+	    
+	}
+	// send the query to all colls
+	Element query_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to_att.toString(), lang, "");
+	query_message.appendChild(query_request);
+	// should we add params individually?
+	Element new_param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	query_request.appendChild(new_param_list);
+	new_param_list.appendChild(this.doc.importNode(GSXML.getNamedElement(param_list, GSXML.PARAM_ELEM, GSXML.NAME_ATT, QUERY_PARAM), true));
+	Element query_result = this.router.process(query_message);
+	
+	// gather up the data from each response
+	int numDocsMatched = 0;
+	int numDocsReturned = 0;
+
+	//term info??
+
+	NodeList metadata = query_result.getElementsByTagName(GSXML.METADATA_ELEM);
+	for (int j=0; j<metadata.getLength(); j++) {
+	    Element meta = (Element)metadata.item(j);
+	    if (meta.getAttribute(GSXML.NAME_ATT).equals("numDocsReturned")) {
+		numDocsReturned += Integer.parseInt(GSXML.getValue(meta));
+	    } else if (meta.getAttribute(GSXML.NAME_ATT).equals("numDocsMatched")) {
+		numDocsMatched += Integer.parseInt(GSXML.getValue(meta));
+	    }
+	}
+	
+	Element metadata_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(metadata_list);
+	GSXML.addMetadata(this.doc, metadata_list, "numDocsReturned", ""+numDocsReturned);
+	//GSXML.addMetadata(this.doc, metadata_list, "numDocsMatched", ""+numDocsMatched);
+
+	Element doc_node_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(doc_node_list);
+	
+	NodeList responses = query_result.getElementsByTagName(GSXML.RESPONSE_ELEM);
+	
+	for (int k=0; k<responses.getLength(); k++) {
+	    String coll_name = GSPath.removeLastLink(((Element)responses.item(k)).getAttribute(GSXML.FROM_ATT));
+	    NodeList nodes = ((Element)responses.item(k)).getElementsByTagName(GSXML.DOC_NODE_ELEM);
+	    if (nodes==null || nodes.getLength()==0) continue;
+	    Element last_node = null;
+	    Element this_node = null;
+	    for (int n=0; n<nodes.getLength(); n++) {
+		this_node = (Element)nodes.item(n);
+		this_node.setAttribute("collection", coll_name);
+		if (k==0) {
+
+		    doc_node_list.appendChild(this.doc.importNode(this_node, true));
+		} else {
+		    if (last_node==null) {
+			last_node = (Element)GSXML.getChildByTagName(doc_node_list, GSXML.DOC_NODE_ELEM);
+		    }
+		    last_node = GSXML.insertIntoOrderedList(doc_node_list, GSXML.DOC_NODE_ELEM, last_node, this_node, "rank", true);
+		}
+		
+	    }
+	}
+	return result;
+    }
+
+//     protected Element processAdvTextQuery(Element request) 
+//     {
+	
+//     }
+    protected boolean initCollectionList() {
+	String lang="en";
+	String uid = "";
+	// first, get the message router info
+	Element coll_list_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element coll_list_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, "", lang, ""); // uid
+	coll_list_message.appendChild(coll_list_request);
+	logger.debug("coll list request = "+this.converter.getPrettyString(coll_list_request));
+	Element coll_list_response = (Element)this.router.process(coll_list_message);
+	if (coll_list_response==null) {
+	    logger.error("couldn't query the message router!");
+	    return false;
+	}
+	logger.debug("coll list response = "+this.converter.getPrettyString(coll_list_response));
+	// second, get some info from each collection. we want the coll name 
+	// and whether its got a text query service 
+	
+	NodeList colls = coll_list_response.getElementsByTagName(GSXML.COLLECTION_ELEM);
+	// we will send all the requests in a single message
+	Element metadata_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	for (int i=0; i<colls.getLength(); i++) {
+	    Element c = (Element)colls.item(i);
+	    String name = c.getAttribute(GSXML.NAME_ATT);	    
+	    Element metadata_request = GSXML.createBasicRequest(this.doc,  GSXML.REQUEST_TYPE_DESCRIBE, name, lang, uid);
+	    metadata_message.appendChild(metadata_request);
+	}
+	logger.debug("metadata request = "+this.converter.getPrettyString(metadata_message));
+	Element metadata_response = (Element)this.router.process(metadata_message);
+	logger.debug("metadata response = "+this.converter.getPrettyString(metadata_response));
+	NodeList coll_responses = metadata_response.getElementsByTagName(GSXML.RESPONSE_ELEM);
+	ArrayList valid_colls = new ArrayList();
+	ArrayList valid_coll_names = new ArrayList();
+	for (int i=0; i<coll_responses.getLength(); i++) {
+	    Element response = (Element)coll_responses.item(i);
+	    Element coll = (Element)GSXML.getChildByTagName(response, GSXML.COLLECTION_ELEM);
+	    Element service_list = (Element)GSXML.getChildByTagName(coll, GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER);
+	    if (service_list==null) continue;
+	    Element query_service = GSXML.getNamedElement(service_list, GSXML.SERVICE_ELEM, GSXML.NAME_ATT, TEXT_QUERY_SERVICE); // should be AbstractSearch.TEXT_QUERY_SERVICE
+	    if (query_service == null) continue;
+	    // use the name of the response in case we are talking to a remote collection, not the name of the collection.
+	    String coll_id = response.getAttribute(GSXML.FROM_ATT);
+	    String coll_name = coll_id+": "+GSXML.getDisplayText(coll, GSXML.DISPLAY_TEXT_NAME, "en", "en"); // just use english for now until we do some caching or something
+	    valid_colls.add(coll_id);
+	    valid_coll_names.add(coll_name);
+	}
+
+	if (valid_colls.size()==0) {
+	    return false;
+	}
+	// ids no all has the list without 'all' option.
+	this.coll_ids_list_no_all = new String[1];
+	this.coll_ids_list_no_all = (String []) valid_colls.toArray(coll_ids_list_no_all);
+	
+	valid_colls.add(0, "all");
+	valid_coll_names.add(0, getTextString("param."+COLLECTION_PARAM+".all", "en" ));
+	this.coll_ids_list = new String[1];
+	this.coll_names_list = new String[1];
+	this.coll_ids_list = (String []) valid_colls.toArray(coll_ids_list);
+	this.coll_names_list = (String []) valid_coll_names.toArray(coll_names_list);
+	return true;
+    }
+
+    protected Element processDocumentMetadataRetrieve(Element request) {
+	// Create a new (empty) result message
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.setAttribute(GSXML.FROM_ATT, DOCUMENT_METADATA_RETRIEVE_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	// Get the parameters of the request
+	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (param_list == null) {
+	    logger.error("DocumentMetadataRetrieve request had no paramList.");
+	    return result;  // Return the empty result
+	}
+
+	NodeList query_doc_list = request.getElementsByTagName(GSXML.DOC_NODE_ELEM);
+	if (query_doc_list.getLength()==0) {
+	   logger.error("DocumentMetadataRetrieve request had no documentNodes.");
+	    return result;  // Return the empty result
+	} 
+	
+	// the resulting doc node list
+	Element result_node_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(result_node_list);
+
+	// get all the metadata params
+	Element new_param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	Element param = GSXML.createParameter(this.doc, "metadata", "Title");
+	new_param_list.appendChild(param);
+	
+	// organise the nodes into collection lists
+	HashMap coll_map = new HashMap();
+	
+	for (int i=0; i<query_doc_list.getLength(); i++) {
+	    Element doc_node = (Element)query_doc_list.item(i);
+	    String coll_name = doc_node.getAttribute("collection");
+	    Element coll_items = (Element)coll_map.get(coll_name);
+	    if (coll_items==null) {
+		coll_items=this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+		coll_map.put(coll_name, coll_items);
+	    }
+	    coll_items.appendChild(this.doc.importNode(doc_node, true));
+	}
+
+	// create teh individual requests
+	Element meta_request_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Set mapping_set = coll_map.entrySet();
+	Iterator iter = mapping_set.iterator();
+
+	while (iter.hasNext()) {
+	    Map.Entry e = (Map.Entry)iter.next();
+	    String cname = (String)e.getKey();
+	    Element doc_nodes = (Element)e.getValue();
+	    Element meta_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, GSPath.appendLink(cname, DOCUMENT_METADATA_RETRIEVE_SERVICE), lang, "");
+	    meta_request.appendChild(doc_nodes);
+	    meta_request.appendChild(new_param_list.cloneNode(true));
+	    meta_request_message.appendChild(meta_request);
+	    
+	}
+
+	Element meta_result = this.router.process(meta_request_message);
+	
+	// now need to put the doc nodes back in the right order
+	// go through the original list again. keep an element pointer to
+	// the next element in each collections list
+	NodeList meta_responses = meta_result.getElementsByTagName(GSXML.RESPONSE_ELEM);
+	for (int i=0; i<meta_responses.getLength(); i++) {
+	    String collname = GSPath.removeLastLink(((Element)meta_responses.item(i)).getAttribute(GSXML.FROM_ATT));
+	    Element first_elem = (Element)GSXML.getNodeByPath(meta_responses.item(i), "documentNodeList/documentNode");
+	    coll_map.put(collname, first_elem);
+	}
+
+	for (int i=0; i<query_doc_list.getLength(); i++) {
+	    Element doc_node = (Element)query_doc_list.item(i);
+	    Element new_node = (Element)this.doc.importNode(doc_node, false);
+	    result_node_list.appendChild(new_node);
+	    String coll_name = doc_node.getAttribute("collection");
+	
+	    Element meta_elem = (Element)coll_map.get(coll_name);
+	    GSXML.mergeMetadataLists(new_node, meta_elem);
+	    coll_map.put(coll_name, meta_elem.getNextSibling());
+	}
+	return result;
+    }
+}
+ 
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/FedoraSearch.java.tmp
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/FedoraSearch.java.tmp	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/FedoraSearch.java.tmp	(revision 14125)
@@ -0,0 +1,302 @@
+package org.greenstone.gsdl3.service;
+
+// Greenstone classes
+import org.greenstone.gsdl3.util.*;
+
+//Fedora Web Services classes
+import fedora.client.utility.AutoFinder;
+import fedora.client.APIAStubFactory;
+import fedora.client.Downloader;
+import fedora.server.access.FedoraAPIA;
+import fedora.server.types.gen.FieldSearchQuery;
+import fedora.server.types.gen.FieldSearchResult;
+import fedora.server.types.gen.ListSession;
+import fedora.server.types.gen.ObjectFields;
+import fedora.server.types.gen.Condition;
+import fedora.server.types.gen.ComparisonOperator;
+
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.transform.Templates;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+
+// XML classes
+import org.w3c.dom.Element; 
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList; 
+
+//Java classes
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Properties;
+import java.io.File;
+import java.io.InputStream;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URLConnection;
+import java.net.URL;
+import java.net.Authenticator;
+import java.net.MalformedURLException;
+import java.lang.Object;
+
+
+/**
+ *
+ * @author <a href="mailto:chi@cs.waikato.ac.nz">Chi-Yu Huang</a>
+ * @version $Revision$
+ *
+ */
+
+public class FedoraSearch
+    extends AbstractSearch {
+    
+    // the services on offer
+    // these strings must match what is found in the properties file
+    protected static final String FIELD_PARAM = "fields";
+    
+    //Parameters connect to Proxy Server
+    private String proxyUser = null;
+    private String proxyPassword = null;
+    
+    private int maxResult, matchNum;
+    
+    protected String fedora_server_url = null;
+    
+    public FedoraSearch()
+    {
+    }
+    
+    //Configure FedoraSearch Service
+    public boolean configure(Element info, Element extra_info) 
+    { 
+	Element server_elem = (Element)GSXML.getChildByTagName(info, "fedoraServer");
+	if (server_elem == null) {
+	    System.err.println("FedoraSearch.configure error: no fedoraServer element found");
+	    return false;
+	}
+	fedora_server_url = server_elem.getAttribute("url");
+	System.err.println("Fedora Server:" + fedora_server_url);
+
+	if (fedora_server_url.equals("")) {
+	    System.err.println("FedoraSearch.configure error: no url for the fedoraServer element");
+	    return false;
+	}
+	Element tq_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	tq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
+	tq_service.setAttribute(GSXML.NAME_ATT, TEXT_QUERY_SERVICE);
+	this.short_service_info.appendChild(tq_service);
+	//does_paging = true;
+	
+	// add some format info to service map if there is any
+	String path = GSPath.appendLink(GSXML.SEARCH_ELEM, GSXML.FORMAT_ELEM);
+	Element format = (Element) GSXML.getNodeByPath(extra_info, path);
+	if (format != null) {
+	    this.format_info_map.put(TEXT_QUERY_SERVICE, this.doc.importNode(format, true));
+	}
+	return true;
+    }
+    
+    /** Process a text query - implemented by concrete subclasses */
+    protected Element processTextQuery(Element request) {
+	// Create a new (empty) result message
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.setAttribute(GSXML.FROM_ATT, TEXT_QUERY_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+	
+	Element doc_node_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(doc_node_list);
+	
+	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (param_list == null) {
+	    System.err.println("FedoraSearch Error:: TextQuery request had no paramList.");
+	    return result;  // Return the empty result
+	}
+	
+	// Process the request parameters
+	HashMap params = GSXML.extractParams(param_list, false);
+	
+	// Make sure a query has been specified
+	String query = (String) params.get(QUERY_PARAM);
+	if (query == null || query.equals("")) {
+	    return result;  // Return the empty result
+	}
+	//Check Max number of Documents hit
+	String maxDocs = (String) params.get(MAXDOCS_PARAM);
+       	String hits_per_page = (String) params.get(HITS_PER_PAGE_PARAM);
+	
+	//Check the start_page number
+	String start_page = (String) params.get(START_PAGE_PARAM);	
+
+	// tidy whitespace
+	//query = query.replaceAll("\\s+", "+");
+	matchNum = 0;
+	maxResult = 20;
+
+	try {
+	    //Search Fedora Server
+	    String host = "toetoe";
+	    int port = 8200;
+	    String user = "fedoraAdmin";
+	    String pass = "fedoraAdmin";
+	    
+	    AutoFinder finder=new AutoFinder(host, port, user, pass);
+
+	    String[] fieldsArray = new String[] {"pid", "label", "fType", "bDef",
+						 "bMech", "cModel", "state", "ownerId", "cDate", "mDate",
+						 "dcmDate", "title", "creator", "subject", "description",
+						 "publisher", "contributor", "date", "type", "format",
+						 "identifier", "source", "language", "relation", "coverage",
+						 "rights"};
+	    
+	    String match_fields = join(fieldsArray, "|");
+	    
+	    FieldSearchQuery query_fedora=fedoraSearch(query, match_fields);
+	    
+            FieldSearchResult result_fedora = finder.findObjects(fieldsArray, maxResult, query_fedora);
+	    
+	    while (result_fedora != null) {
+		System.err.println("Search Result:" + result_fedora.getResultList().length);
+		for (int i=0; i<result_fedora.getResultList().length; i++) {
+		    ObjectFields o = result_fedora.getResultList()[i];
+		    matchNum++;
+		    String pid = o.getPid();
+		    String fedora_url = fedora_server_url +"/fedora/get/" + pid;
+		    String label = o.getLabel();
+		    String[] creator = o.getCreator();
+		    String[] subject = o.getSubject();
+		    String[] publisher = o.getPublisher();
+		    String[] contributor = o.getContributor();
+		    String[] title = o.getTitle();
+		    String[] description = o.getDescription();
+		    String[] format = o.getFormat();
+		    String[] identifier = o.getIdentifier();
+		    String[] source = o.getSource();
+		    String[] language = o.getLanguage();
+
+		    Element doc_node = this.doc.createElement(GSXML.DOC_NODE_ELEM);
+		    doc_node_list.appendChild(doc_node);
+		    
+		    Element metadata_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+		    doc_node.appendChild(metadata_list);
+		    
+		    if (fedora_url != null) {
+			GSXML.addMetadata(this.doc, metadata_list, "URL", fedora_url);
+		    }
+		    if (o.getDescription() != null) {
+			GSXML.addMetadata(this.doc, metadata_list, "Description", description[0]);
+		    }
+		    if (title[0] != null) {
+			GSXML.addMetadata(this.doc, metadata_list, "Title", title[0]);
+		    }
+		}
+		ListSession sess=result_fedora.getListSession();
+		if (sess!=null) {
+		    result_fedora = finder.resumeFindObjects(sess.getToken());
+		} else {
+		    result_fedora = null;
+		}
+	    }
+	} catch (Exception e) {
+	    System.err.println("ERROR: " + e.getClass().getName()
+			       + ((e.getMessage()==null) ? "" : ": " + e.getMessage()));
+	}
+    	
+	Element metadata_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(metadata_list);
+	
+	// Add a metadata element specifying the number of matching documents
+	//System.err.println("FedoraSearch Number of Documents:" + matchNum);
+	GSXML.addMetadata(this.doc, metadata_list, "numDocsMatched", ""+matchNum);
+	
+	return result;
+    }
+
+    protected FieldSearchQuery fedoraSearch(String query_terms, String matchFields) {
+
+	FieldSearchQuery fedora_query=new FieldSearchQuery();
+	try {
+	    // check if query contains any fields name (pid, label, fType....)
+	    if (query_terms.matches("^("+ matchFields+").+")){
+		System.err.println("Implementing Specific Query....");
+
+		List conditions=fedora.server.search.Condition.getConditions(query_terms);
+		
+		Condition[] cond=new Condition[conditions.size()];
+		for (int i=0; i<conditions.size(); i++) {
+		    fedora.server.search.Condition c = (fedora.server.search.Condition) conditions.get(i);
+		    try {
+			String operator = transOperator(c.getOperator().getAbbreviation());
+			cond[i] = new Condition();
+			cond[i].setProperty(c.getProperty());
+			cond[i].setOperator(ComparisonOperator.fromValue(operator));
+			cond[i].setValue(c.getValue());
+		    } catch (Exception e){
+			e.printStackTrace();
+		    }
+		}
+		fedora_query.setConditions(cond);
+	    } else {
+		System.err.println("Implementing Simple Query...");
+		fedora_query.setTerms(query_terms);
+	    }
+	} catch (Exception e){
+	    e.printStackTrace();
+	}
+	return fedora_query;
+    }
+    
+    protected void getIndexData(ArrayList index_ids, ArrayList index_names,String lang){
+       	index_ids.add("kw");
+	index_ids.add("au");	
+	index_ids.add("su");	
+	index_ids.add("ti");
+	index_ids.add("de");
+	index_ids.add("fu");
+	index_names.add(getTextString("param."+FIELD_PARAM+".kw", lang)); 
+	index_names.add(getTextString("param."+FIELD_PARAM+".au", lang));
+	index_names.add(getTextString("param."+FIELD_PARAM+".su", lang));
+	index_names.add(getTextString("param."+FIELD_PARAM+".ti", lang));
+	index_names.add(getTextString("param."+FIELD_PARAM+".de", lang));
+	index_names.add(getTextString("param."+FIELD_PARAM+".fu", lang));
+    }
+    
+    protected String getDocType (String node_id){
+	return node_id;
+    }
+    protected boolean hasChildren(String node_id){
+	return false;
+    }
+
+    protected boolean hasParent(String node_id){
+	return false;
+    }
+    private String transOperator(String operator){
+	String oper_char ="";
+	if (operator == "~") {
+	    oper_char = "has";
+	} else if (operator == "=") {
+	    oper_char = "eq";
+	} else if (operator == ">"){
+	    oper_char = "gt";
+	} else if (operator == ">="){
+	    oper_char = "ge";
+	} else if (operator == "<"){
+	    oper_char = "lt";
+   	} else if (operator == "<="){
+	    oper_char = "le";
+	}
+	return oper_char;
+    }
+    protected String join( String[] array, String delim ) {
+        String j = "";
+        for ( int i=0; i<array.length; i++ ) {
+            if (i!=0) j += delim;
+            j += array[i];
+        }
+        return j;
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2Browse.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2Browse.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2Browse.java	(revision 14125)
@@ -0,0 +1,299 @@
+/*
+ *    GS2Browse.java
+ *    Copyright (C) 2005 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.service;
+
+// Greenstone classes
+import org.greenstone.gsdl3.util.OID;
+import org.greenstone.gsdl3.util.GSXML;
+import org.greenstone.gsdl3.util.GSFile;
+import org.greenstone.gsdl3.util.MacroResolver;
+import org.greenstone.gsdl3.util.GS2MacroResolver;
+import org.greenstone.gsdl3.util.GDBMWrapper;
+import org.greenstone.gsdl3.util.DBInfo;
+// XML classes
+import org.w3c.dom.Document;
+import org.w3c.dom.Element; 
+import org.w3c.dom.NodeList;
+
+// General Java classes
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+import java.util.Set;
+import java.util.Iterator;
+
+import org.apache.log4j.*;
+
+/** Greenstone 2 collection classifier service
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @author <a href="mailto:mdewsnip@cs.waikato.ac.nz">Michael Dewsnip</a>
+ */
+
+public class GS2Browse 
+    extends AbstractBrowse 
+{
+
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.GS2Browse.class.getName());
+
+    protected GDBMWrapper gdbm_src = null;
+
+    public GS2Browse() 
+    {
+	this.gdbm_src = new GDBMWrapper();
+	this.macro_resolver = new GS2MacroResolver(this.gdbm_src);
+    }
+
+    public void cleanUp() {
+	super.cleanUp();
+	this.gdbm_src.closeDatabase();
+    }
+
+    public boolean configure(Element info, Element extra_info)
+    {
+	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+
+	logger.info("Configuring GS2Browse...");
+	// the index stem is either specified in the config file or is  the collection name
+	Element index_stem_elem = (Element) GSXML.getChildByTagName(info, GSXML.INDEX_STEM_ELEM);
+	String index_stem = null;
+	if (index_stem_elem != null) {
+	    index_stem = index_stem_elem.getAttribute(GSXML.NAME_ATT);
+	}
+	if (index_stem == null || index_stem.equals("")) {
+	    index_stem = this.cluster_name;
+	}
+	
+	// Open GDBM database for querying
+	String gdbm_db_file = GSFile.GDBMDatabaseFile(this.site_home, this.cluster_name, index_stem);
+	if (!this.gdbm_src.openDatabase(gdbm_db_file, GDBMWrapper.READER)) {
+	    logger.error("Could not open GDBM database!");
+	    return false;
+	}
+	return true;
+    }
+
+    /** if id ends in .fc, .pc etc, then translate it to the correct id */
+    protected String translateId(String node_id) {
+	return this.gdbm_src.translateOID(node_id);
+    }
+
+    /** returns the document type of the doc that the specified node 
+	belongs to. should be one of 
+	GSXML.DOC_TYPE_SIMPLE, 
+	GSXML.DOC_TYPE_PAGED, 
+	GSXML.DOC_TYPE_HIERARCHY
+    */
+    protected String getDocType(String node_id) {
+	DBInfo info = this.gdbm_src.getInfo(node_id);
+	if (info == null) {
+	    return GSXML.DOC_TYPE_SIMPLE;
+	}
+	String doc_type = info.getInfo("doctype");
+	if (!doc_type.equals("")&&!doc_type.equals("doc")) {
+	    return doc_type;
+	}
+
+	String top_id = OID.getTop(node_id);
+	boolean is_top = (top_id.equals(node_id) ? true : false);
+	
+	String children = info.getInfo("contains");
+	boolean is_leaf = (children.equals("") ? true : false);
+
+	if (is_top && is_leaf) { // a single section document
+	    return GSXML.DOC_TYPE_SIMPLE;
+	}
+
+	// now we just check the top node
+	if (!is_top) { // we need to look at the top info
+	    info = this.gdbm_src.getInfo(top_id);
+	}
+	if (info == null) {
+	    return GSXML.DOC_TYPE_HIERARCHY;
+	}
+ 
+	String childtype = info.getInfo("childtype");
+	if (childtype.equals("Paged")) {
+	    return GSXML.DOC_TYPE_PAGED;
+	}
+	return GSXML.DOC_TYPE_HIERARCHY;
+
+    }
+
+    /** returns the id of the root node of the document containing node node_id. . may be the same as node_id */
+    protected String getRootId(String node_id) {
+	return OID.getTop(node_id);
+    }
+    /** returns a list of the child ids in order, null if no children */
+    protected ArrayList getChildrenIds(String node_id) {
+	DBInfo info = this.gdbm_src.getInfo(node_id);
+	if (info == null) {
+	    return null;
+	}
+
+	ArrayList children = new ArrayList();
+	
+	String contains = info.getInfo("contains");
+	StringTokenizer st = new StringTokenizer(contains, ";");
+	while (st.hasMoreTokens()) {
+	    String child_id = st.nextToken().replaceAll("\"", node_id);
+	    children.add(child_id);
+	}
+	return children;
+
+    }
+    /** returns the node id of the parent node, null if no parent */
+    protected String getParentId(String node_id){
+	String parent = OID.getParent(node_id);
+	if (parent.equals(node_id)) {
+	    return null;
+	}
+	return parent;
+    }
+
+    protected String getMetadata(String node_id, String key){
+	DBInfo info = this.gdbm_src.getInfo(node_id);
+	if (info == null) {
+	    return "";
+	}
+
+	Set keys = info.getKeys();
+	Iterator it = keys.iterator();
+	while(it.hasNext()) {
+	    String key_in = (String)it.next();
+	    String value = info.getInfo(key);
+	    if (key_in.equals(key)){
+		return value;
+	    }
+	}
+	
+	return "";
+
+    }
+
+    /** get the metadata for the classifier node node_id
+     * returns a metadataList element:
+     * <metadataList><metadata name="xxx">value</metadata></metadataList>
+     * if all_metadata is true, returns all available metadata, otherwise just
+     * returns requested metadata
+     */
+    // assumes only one value per metadata
+    protected Element getMetadataList(String node_id, boolean all_metadata, 
+				      ArrayList metadata_names) {
+	String lang = "en";
+	Element metadata_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+	DBInfo info = this.gdbm_src.getInfo(node_id);
+	if (info == null) {
+	    return null;
+	}
+	if (all_metadata) {
+	    // return everything out of the database
+	    Set keys = info.getKeys();
+	    Iterator it = keys.iterator();
+	    while(it.hasNext()) {
+		String key = (String)it.next();
+		String value = info.getInfo(key);
+		GSXML.addMetadata(this.doc, metadata_list, key, this.macro_resolver.resolve(value, lang, GS2MacroResolver.SCOPE_META, node_id));
+	    }
+	    
+	} else {
+	    for (int i=0; i<metadata_names.size(); i++) {
+		String meta_name = (String) metadata_names.get(i);
+		String value = (String)info.getInfo(meta_name);
+		GSXML.addMetadata(this.doc, metadata_list, meta_name, value);
+	    }
+	}
+	return metadata_list;
+    }
+
+    /** returns the structural information asked for.
+     * info_type may be one of
+     * INFO_NUM_SIBS, INFO_NUM_CHILDREN, INFO_SIB_POS
+     */
+    protected String getStructureInfo(String doc_id, String info_type) {
+	String value="";
+	if (info_type.equals(INFO_NUM_SIBS)) {
+	    String parent_id = OID.getParent(doc_id);
+	    if (parent_id.equals(doc_id)) {
+		value="0";
+	    } else {
+		value = String.valueOf(getNumChildren(parent_id));
+	    }
+	    return value;
+	}
+	
+	if (info_type.equals(INFO_NUM_CHILDREN)) {
+	    return String.valueOf(getNumChildren(doc_id));
+	}
+
+	
+	if (info_type.equals(INFO_SIB_POS)) {
+	    String parent_id = OID.getParent(doc_id);
+	    if (parent_id.equals(doc_id)) {
+		return "-1";
+	    }
+	    
+	    DBInfo info = this.gdbm_src.getInfo(parent_id);
+	    if (info==null) {
+		return "-1";
+	    }
+	    
+	    String contains = info.getInfo("contains");
+	    contains = contains.replaceAll("\"", parent_id);
+	    String [] children = contains.split(";");
+	    for (int i=0;i<children.length;i++) {
+		String child_id = children[i];
+		if (child_id.equals(doc_id)) {
+		    return String.valueOf(i+1); // make it from 1 to length
+			   
+		}
+	    }
+	    
+	    return "-1";
+	} else {
+	    return null;
+	}
+
+    }
+
+    protected int getNumChildren(String node_id) {
+	DBInfo info = this.gdbm_src.getInfo(node_id);
+	if (info == null) {
+	    return 0;
+	}
+	String contains = info.getInfo("contains");
+	if (contains.equals("")) {
+	    return 0;
+	}
+	String [] children = contains.split(";");
+	return children.length;
+    }
+    
+    /** returns true if the id refers to a document (rather than 
+     * a classifier node)
+     */
+    protected boolean isDocumentId(String node_id){
+	if (node_id.startsWith("CL")) {
+	    return false;
+	}
+	return true;
+    }
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2Construct.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2Construct.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2Construct.java	(revision 14125)
@@ -0,0 +1,572 @@
+/*
+ *    GS2Construct.java 
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.service;
+
+import org.greenstone.gsdl3.util.*;
+import org.greenstone.gsdl3.build.*;
+
+import org.w3c.dom.Document; 
+import org.w3c.dom.Node; 
+import org.w3c.dom.Text; 
+import org.w3c.dom.Element; 
+import org.w3c.dom.NodeList; 
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
+import java.io.File;
+import java.util.Locale;
+
+import org.apache.log4j.*;
+
+/**
+ * A Services class for building collections
+ * provides a wrapper around the old perl scripts
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @version $Revision$
+ */
+public class GS2Construct 
+    extends ServiceRack { 
+    
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.GS2Construct.class.getName()); 
+
+    // services offered
+    private static final String NEW_SERVICE = "NewCollection";
+    private static final String ADD_DOC_SERVICE = "AddDocument";
+    private static final String IMPORT_SERVICE = "ImportCollection";
+    private static final String BUILD_SERVICE = "BuildCollection";
+    private static final String ACTIVATE_SERVICE = "ActivateCollection";
+    private static final String DELETE_SERVICE = "DeleteCollection";
+    private static final String RELOAD_SERVICE = "ReloadCollection";
+
+    // params used
+    private static final String COL_PARAM = "collection";
+    private static final String NEW_COL_TITLE_PARAM = "collTitle";
+    private static final String NEW_COL_ABOUT_PARAM = "collAbout";
+    private static final String CREATOR_PARAM = "creator";
+    private static final String NEW_FILE_PARAM = "newfile";
+    private static final String PROCESS_ID_PARAM = GSParams.PROCESS_ID;
+    private static final String BUILDTYPE_PARAM = "buildType";
+    private static final String BUILDTYPE_MG = "mg";
+    private static final String BUILDTYPE_MGPP = "mgpp";
+    
+    // the list of the collections - store between some method calls
+    private String[] collection_list = null;
+
+    // set of listeners for any construction commands
+    protected Map listeners = null;
+    
+    public GS2Construct() {
+	this.listeners = Collections.synchronizedMap(new HashMap());
+	
+    }
+
+    /** returns a specific service description */
+    protected Element getServiceDescription(String service, String lang, String subset) {
+
+	Element description = this.doc.createElement(GSXML.SERVICE_ELEM);
+	description.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
+	description.setAttribute(GSXML.NAME_ATT, service);
+	if (subset == null || subset.equals(GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER)) {
+	    description.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_NAME,  getTextString(service+".name", lang)));
+	    description.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_DESCRIPTION,  getTextString(service+".description", lang)));
+	    description.appendChild(GSXML.createDisplayTextElement(this.doc,  GSXML.DISPLAY_TEXT_SUBMIT, getTextString(service+".submit", lang)));
+	}
+	if (subset == null || subset.equals(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER)) {
+	    Element param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	    description.appendChild(param_list);
+	    
+	    if (service.equals(NEW_SERVICE)) {
+		
+		Element param = GSXML.createParameterDescription(this.doc, NEW_COL_TITLE_PARAM, getTextString("param."+NEW_COL_TITLE_PARAM, lang), GSXML.PARAM_TYPE_STRING, null, null, null);
+		param_list.appendChild(param);
+		param = GSXML.createParameterDescription(this.doc, CREATOR_PARAM, getTextString("param."+CREATOR_PARAM, lang), GSXML.PARAM_TYPE_STRING, null, null, null);
+		param_list.appendChild(param);
+		param = GSXML.createParameterDescription(this.doc, NEW_COL_ABOUT_PARAM, getTextString("param."+NEW_COL_ABOUT_PARAM, lang), GSXML.PARAM_TYPE_TEXT, null, null, null);
+		param_list.appendChild(param);
+		String[] types = {BUILDTYPE_MGPP, BUILDTYPE_MG};
+		String[] type_texts = {getTextString("param."+BUILDTYPE_PARAM+"."+BUILDTYPE_MGPP, lang), getTextString("param."+BUILDTYPE_PARAM+"."+BUILDTYPE_MG, lang)};
+		
+		param = GSXML.createParameterDescription(this.doc, BUILDTYPE_PARAM, getTextString("param."+BUILDTYPE_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, BUILDTYPE_MGPP, types, type_texts);
+		param_list.appendChild(param);
+	    }
+	    else if (service.equals(ACTIVATE_SERVICE) || service.equals(IMPORT_SERVICE) || service.equals(BUILD_SERVICE) || service.equals(RELOAD_SERVICE) || service.equals(DELETE_SERVICE)) {
+	    
+		this.collection_list = getCollectionList();
+		Element param = GSXML.createParameterDescription(this.doc, COL_PARAM, getTextString("param."+COL_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, null, this.collection_list, this.collection_list);	
+		param_list.appendChild(param);
+	    } else {
+		// invalid service name
+		return null;
+	    }
+	}
+	return description;
+    }
+
+    // each service must have a method "process<New service name>"
+
+    protected Element processNewCollection(Element request) {
+	return runCommand(request, GS2PerlConstructor.NEW);	
+    }
+    
+    /** TODO:implement this */
+    protected Element processAddDocument(Element request) {
+	// decode the file name, add it to the import directory
+	String name = GSPath.getFirstLink(request.getAttribute(GSXML.TO_ATT));
+	Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	response.setAttribute(GSXML.FROM_ATT, name);
+	Element status = this.doc.createElement(GSXML.STATUS_ELEM);
+	response.appendChild(status);
+	//String lang = request.getAttribute(GSXML.LANG_ATT);
+	//String request_type = request.getAttribute(GSXML.TYPE_ATT);
+	Text t = this.doc.createTextNode("AddDocument: not implemented yet");
+	status.appendChild(t);
+	status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
+	return response;
+    }
+    protected Element processImportCollection(Element request) {
+	return runCommand(request, GS2PerlConstructor.IMPORT);
+    }
+
+    protected Element processBuildCollection(Element request) {
+	return runCommand(request, GS2PerlConstructor.BUILD);
+    }
+    protected Element processActivateCollection(Element request) {
+	Element response = runCommand(request, GS2PerlConstructor.ACTIVATE);
+	// this activates the collection on disk. but now we need to tell
+	// the MR about it. but we have to wait until the process is finished.
+	Element status = (Element)GSXML.getChildByTagName(response, GSXML.STATUS_ELEM);
+	Element param_list = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	HashMap params = GSXML.extractParams(param_list, false);
+	String coll_name = (String) params.get(COL_PARAM);
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	// check for finished
+	int status_code = Integer.parseInt(status.getAttribute(GSXML.STATUS_ERROR_CODE_ATT));
+	if (GSStatus.isCompleted(status_code) && 
+	    GSStatus.isError(status_code)) {
+	    // we shouldn't carry out the next bit, just return the response
+	    return response;
+	}
+	String id = status.getAttribute(GSXML.STATUS_PROCESS_ID_ATT);
+	GS2PerlListener listener = (GS2PerlListener)this.listeners.get(id);
+	if (listener==null) {
+	    logger.error("somethings gone wrong, couldn't find the listener");
+	    status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
+	    return response;
+	}
+	while (!GSStatus.isCompleted(status_code)) {
+	    // wait for the process, and keep checking the status code
+	    // there is probably a better way to do this.
+	    try {
+		Thread.currentThread().sleep(100);
+	    } catch (Exception e) { // ignore
+	    }
+	    status_code = listener.getStatus();
+	}
+	
+	// add the rest of the messages to the status node
+	Text t = this.doc.createTextNode("\n"+listener.getUpdate());
+	status.appendChild(t);
+	status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(listener.getStatus()));
+	if (GSStatus.isError(status_code)) {
+	    return response; // without doing the next bit
+	}
+
+	t = this.doc.createTextNode("\n");
+	status.appendChild(t);
+	// once have got here, we assume
+	// the first bit proceeded successfully, now reload the collection
+	systemRequest("reload", coll_name, status, lang); // this will append more messages to the status, and overwrite the error code att
+	return response;
+	
+    }
+    protected Element processDeleteCollection(Element request) {
+
+	// the response to send back
+	String name = GSPath.getFirstLink(request.getAttribute(GSXML.TO_ATT));
+	Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	response.setAttribute(GSXML.FROM_ATT, name);
+	Element status = this.doc.createElement(GSXML.STATUS_ELEM);
+	response.appendChild(status);
+	Text t = null; // the text node for the error/success message
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	String request_type = request.getAttribute(GSXML.TYPE_ATT);
+	
+	Element param_list = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	HashMap params = GSXML.extractParams(param_list, false);
+	
+	boolean get_status_only = false;
+	if (request_type.equals(GSXML.REQUEST_TYPE_STATUS)) {
+	    get_status_only = true;
+	}
+	if (get_status_only) {
+	    // at the moment, delete is synchronous. but it may take ages so should do the command in another thread maybe? in which case we will want to ask for status
+	    logger.error("had a status request for delete - this shouldn't happen!!");
+	    //t = this.doc.createTextNode("");
+	    //status.appendChild(t);
+	    status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
+	    return response;
+	}
+	String coll_name = (String)params.get(COL_PARAM);	
+	String[] args={coll_name};
+	File coll_dir = new File(GSFile.collectionBaseDir(this.site_home, coll_name));
+	// check that the coll is there in the first place
+	if (!coll_dir.exists()) {
+	    t = this.doc.createTextNode(getTextString("delete.exists_error", lang, args));
+	    status.appendChild(t);
+	    status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
+	    return response;
+	}
+		
+	// try to delete the directory
+	if (!GSFile.deleteFile(coll_dir)) {
+	    t = this.doc.createTextNode(getTextString("delete.delete_error", lang, args));
+	    status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
+	    status.appendChild(t);
+	    return response;
+	}
+	systemRequest("delete", coll_name, status, lang);
+	return response;
+    }
+
+    protected Element processReloadCollection(Element request) {
+
+	// the response to send back
+	String name = GSPath.getFirstLink(request.getAttribute(GSXML.TO_ATT));
+	Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	response.setAttribute(GSXML.FROM_ATT, name);
+	Element status = this.doc.createElement(GSXML.STATUS_ELEM);
+	response.appendChild(status);
+	Text t = null; // the text node for the error/success message
+	
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	String request_type = request.getAttribute(GSXML.TYPE_ATT);
+	
+	Element param_list = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	HashMap params = GSXML.extractParams(param_list, false);
+	
+	boolean get_status_only = false;
+	if (request_type.equals(GSXML.REQUEST_TYPE_STATUS)) {
+	    get_status_only = true;
+	}
+	if (get_status_only) {
+	    // reload is synchronous - this makes no sense
+	    logger.error("had a status request for reload - this shouldn't happen!!");
+	    //t = this.doc.createTextNode("");
+	    //status.appendChild(t);
+	    status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
+	    return response;
+	}
+	
+	String coll_name = (String)params.get(COL_PARAM);
+	systemRequest("reload", coll_name, status, lang);
+	return response;	
+	
+    }
+
+    /** send a configure request to the message router 
+     * action name should be "delete" or "reload"
+     * response will be put into the status element
+     */
+    protected void systemRequest(String action_name, String coll_name, Element status, String lang) {
+	
+	// send the request to the MR
+	Element message = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	Element request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_SYSTEM, "", lang, "");
+	message.appendChild(request);
+	Element command = this.doc.createElement(GSXML.SYSTEM_ELEM);
+	request.appendChild(command);
+	command.setAttribute(GSXML.SYSTEM_MODULE_TYPE_ATT, GSXML.COLLECTION_ELEM);
+	command.setAttribute(GSXML.SYSTEM_MODULE_NAME_ATT, coll_name);
+
+	if (action_name.equals("delete")) {
+	    command.setAttribute(GSXML.TYPE_ATT, GSXML.SYSTEM_TYPE_DEACTIVATE);
+	} else if (action_name.equals("reload")) {
+	    command.setAttribute(GSXML.TYPE_ATT, GSXML.SYSTEM_TYPE_ACTIVATE);
+	} else {
+	    logger.error("invalid action name passed to systemRequest:"+action_name);
+	    return;
+	}
+	request.appendChild(command);
+	Element response = this.router.process(message); // at the moment, get no info in response so ignore it
+	Text t;
+	String[] args={coll_name};
+	    
+	if (response == null) {
+	    t = this.doc.createTextNode(getTextString(action_name+".configure_error", lang, args));
+	    status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
+	    status.appendChild(t);
+	    return;
+	}
+	    
+	// if we got here, we have succeeded!
+	t = this.doc.createTextNode(getTextString(action_name+".success", lang, args));
+	status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.SUCCESS));
+	status.appendChild(t);
+    }
+
+
+    /** configure the service module
+     * for now, all services have type=build - need to think about this
+     */
+    public boolean configure(Element info, Element extra_info) {
+	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+
+	logger.info("configuring GS2Construct");
+
+	Element e = null;
+	// hard code in the services for now
+
+	// set up short_service_info_ - for now just has name and type
+
+	e = this.doc.createElement(GSXML.SERVICE_ELEM);
+	e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
+	e.setAttribute(GSXML.NAME_ATT, NEW_SERVICE);
+	this.short_service_info.appendChild(e);
+
+	e = this.doc.createElement(GSXML.SERVICE_ELEM);
+	e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
+	e.setAttribute(GSXML.NAME_ATT, IMPORT_SERVICE);
+	this.short_service_info.appendChild(e);
+
+	e = this.doc.createElement(GSXML.SERVICE_ELEM);
+	e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
+	e.setAttribute(GSXML.NAME_ATT, BUILD_SERVICE);
+	this.short_service_info.appendChild(e);
+
+	e = this.doc.createElement(GSXML.SERVICE_ELEM);
+	e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
+	e.setAttribute(GSXML.NAME_ATT, ACTIVATE_SERVICE);
+	this.short_service_info.appendChild(e);
+
+	e = this.doc.createElement(GSXML.SERVICE_ELEM);
+	e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
+	e.setAttribute(GSXML.NAME_ATT, DELETE_SERVICE);
+	this.short_service_info.appendChild(e);
+
+	e = this.doc.createElement(GSXML.SERVICE_ELEM);
+	e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
+	e.setAttribute(GSXML.NAME_ATT, RELOAD_SERVICE);
+	this.short_service_info.appendChild(e);
+
+	//e = this.doc.createElement(GSXML.SERVICE_ELEM);
+	//e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
+	//e.setAttribute(GSXML.NAME_ATT, ADD_DOC_SERVICE);
+	//this.short_service_info.appendChild(e);
+
+
+	return true;
+    }
+
+    /** returns a response element */
+    protected Element runCommand(Element request, int type ) {
+	
+	// the response to send back
+	String name = GSPath.getFirstLink(request.getAttribute(GSXML.TO_ATT));
+	Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	response.setAttribute(GSXML.FROM_ATT, name);
+	Element status = this.doc.createElement(GSXML.STATUS_ELEM);
+	response.appendChild(status);
+
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	String request_type = request.getAttribute(GSXML.TYPE_ATT);
+
+	Element param_list = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	HashMap params = GSXML.extractParams(param_list, false);
+
+	boolean get_status_only = false;
+	if (request_type.equals(GSXML.REQUEST_TYPE_STATUS)) {
+	    get_status_only = true;
+	}
+	
+	// just check for status messages if that's all that's required
+	if (get_status_only) {
+	    String id = (String)params.get(PROCESS_ID_PARAM);
+	    status.setAttribute(GSXML.STATUS_PROCESS_ID_ATT, id);
+	    GS2PerlListener listener = (GS2PerlListener)this.listeners.get(id);
+	    if (listener==null) {
+		Text t = this.doc.createTextNode(getTextString("general.process_id_error", lang));
+		status.appendChild(t);
+		status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
+	    } else {
+		Text t = this.doc.createTextNode(listener.getUpdate());
+		status.appendChild(t);
+		status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(listener.getStatus()));
+		// check that we actually should be removing the listener here
+		if (listener.isFinished()) { // remove this listener - its job is done
+		    this.listeners.remove(id); // not working
+		}
+	    }
+	    return response;
+
+	}
+
+	// do teh actual command
+	String coll_name=null;
+	if (type==GS2PerlConstructor.NEW) {
+	    String coll_title = (String)params.get(NEW_COL_TITLE_PARAM);
+	    coll_name = createNewCollName(coll_title);
+	} else {
+	    coll_name = (String)params.get(COL_PARAM);
+	}
+	logger.error("Coll name = "+coll_name);
+	// makes a paramList of the relevant params
+	Element other_params = extractOtherParams(params, type);
+
+	//create the constructor to do the work
+
+	GS2PerlConstructor constructor = new GS2PerlConstructor("perl_build");
+	if (!constructor.configure()) {
+	    Text t = this.doc.createTextNode(getTextString("general.configure_constructor_error", lang));
+	    status.appendChild(t);
+	    status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
+	    return response;
+	}
+		
+	constructor.setSiteHome(this.site_home);
+	constructor.setCollectionName(coll_name);
+	constructor.setActionType(type);
+	constructor.setProcessParams(other_params);
+	// the listener
+	GS2PerlListener listener = new GS2PerlListener();
+	constructor.addListener(listener);
+	constructor.start();
+
+	String id = newID();
+	this.listeners.put(id, listener);
+
+	status.setAttribute(GSXML.STATUS_PROCESS_ID_ATT, id);
+	status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ACCEPTED));
+	Text t = this.doc.createTextNode(getTextString("general.process_start", lang));
+	status.appendChild(t);
+	return response;
+
+    }
+
+
+    //************************
+    // some helper functions
+    //************************
+
+    /** parse the collect directory and return a list of collection names */
+    protected String[] getCollectionList() {
+	
+	File collectDir = new File(GSFile.collectDir(this.site_home));
+	if (!collectDir.exists()) {
+	    logger.error("couldn't find collect dir: "+collectDir.toString());
+	    return null;
+	}
+	logger.info("GS2Construct: reading thru directory "+collectDir.getPath()+" to find collections.");
+	File[] contents = collectDir.listFiles();
+	int num_colls=0;
+	for (int i=0; i<contents.length;i++) {
+	    if(contents[i].isDirectory() && !contents[i].getName().startsWith("CVS")) {
+		num_colls ++;
+	    }
+	}
+	
+	String[] names= new String[num_colls];
+	
+	for (int i=0, j=0; i<contents.length;i++) {
+	    if(contents[i].isDirectory()) {
+		String colName = contents[i].getName();
+		if (!colName.startsWith("CVS")) {
+		    names[j] = colName;
+		    j++;
+		}
+		
+	    } 
+	}
+	
+	return names;
+	
+    }
+   
+    /** ids used for process id */
+    private int current_id = 0;
+    private String newID() {
+	current_id++;
+	return Integer.toString(current_id);
+    }
+
+    /** creates a new short name from the collection title */
+    protected String createNewCollName(String coll_title) {
+
+	String base_name = null;
+	// take the first 6 letters
+	if (coll_title.length()<6) {
+	    base_name = coll_title;
+	} else {
+	    base_name = coll_title.substring(0,6);
+	}
+	File coll_dir = new File(GSFile.collectionBaseDir(this.site_home, base_name));
+	if (!coll_dir.exists()) { // this name is ok - not used yet
+	    return base_name;
+	}
+	
+	// now we have to make a new name until we get a good one
+	// try name1, name2 name3 etc
+	int i=0;
+	while(coll_dir.exists()) {
+	    i++;
+	    coll_dir = new File(GSFile.collectionBaseDir(this.site_home, base_name+Integer.toString(i)));
+	}
+	return base_name+Integer.toString(i);
+	
+    }
+
+    /** takes the params from the request (in the HashMap) and extracts any
+     * that need to be passed to the constructor and puts them into a 
+     * paramList element */
+    protected Element extractOtherParams(HashMap params, int type) {
+
+	Element param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (type == GS2PerlConstructor.NEW) {
+	    Element param = this.doc.createElement(GSXML.PARAM_ELEM);
+	    param.setAttribute(GSXML.NAME_ATT, "creator");
+	    param.setAttribute(GSXML.VALUE_ATT, (String)params.get(CREATOR_PARAM));
+	    
+	    param_list.appendChild(param);
+	    param = this.doc.createElement(GSXML.PARAM_ELEM);
+	    param.setAttribute(GSXML.NAME_ATT, "about");
+	    param.setAttribute(GSXML.VALUE_ATT, (String)params.get(NEW_COL_ABOUT_PARAM));
+	    param_list.appendChild(param);
+	    param = this.doc.createElement(GSXML.PARAM_ELEM);
+	    param.setAttribute(GSXML.NAME_ATT, "title");
+	    param.setAttribute(GSXML.VALUE_ATT, (String)params.get(NEW_COL_TITLE_PARAM));
+	    param_list.appendChild(param);
+	    param = this.doc.createElement(GSXML.PARAM_ELEM);
+	    param.setAttribute(GSXML.NAME_ATT, "buildtype");
+	    param.setAttribute(GSXML.VALUE_ATT, (String)params.get(BUILDTYPE_PARAM));
+	    param_list.appendChild(param);
+	    return param_list;
+	}
+
+	// other ones dont have params yet
+	return null;
+    }
+	
+}
+
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2LuceneRetrieve.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2LuceneRetrieve.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2LuceneRetrieve.java	(revision 14125)
@@ -0,0 +1,158 @@
+/*
+ *    GS2LuceneRetrieve.java
+ *    Copyright (C) 2005 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.service;
+
+// Greenstone classes
+import org.greenstone.gsdl3.core.GSException;
+import org.greenstone.gsdl3.util.GSFile;
+import org.greenstone.gsdl3.util.GSXML;
+import org.greenstone.gsdl3.util.GDBMWrapper;
+import org.greenstone.gsdl3.util.DBInfo;
+import org.greenstone.gsdl3.util.GSHTML;
+import org.greenstone.gsdl3.util.OID;
+// XML classes
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Text;
+
+// General Java classes
+import java.io.File;
+
+import org.apache.log4j.Logger;
+
+/** Retrieve documents from a gs2 lucene collection. Note that this doesn't 
+    actually use lucene, as the documents are stored in XML files */
+public class GS2LuceneRetrieve
+    extends AbstractGS2DocumentRetrieve
+{
+    
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.GS2LuceneRetrieve.class.getName());
+    
+    
+    protected static final String DOC_LEVEL="Doc";
+    protected static final String SEC_LEVEL="Sec";
+    protected static final String ID_ATT = "gs2:id";
+
+    // Parameters used
+    private static final String LEVEL_PARAM = "level";
+    
+    // Elements used in the config file that are specific to this class
+    private static final String DEFAULT_LEVEL_ELEM = "defaultLevel";
+    
+    private String default_level = null;
+    private String text_dir = null;
+
+    private boolean text_available = true;
+    
+    public GS2LuceneRetrieve() {
+    }
+    
+    public void cleanUp() {
+	super.cleanUp();
+    }
+    
+    /** configure this service */
+    public boolean configure(Element info, Element extra_info)
+    {
+	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+	
+	// Do specific configuration
+	logger.info("Configuring GS2LuceneRetrieve...");
+	
+	text_dir = GSFile.collectionIndexDir(this.site_home, this.cluster_name) + File.separatorChar+"text"+File.separatorChar;
+	if (!(new File(text_dir).isDirectory())) {
+	    logger.error("Text directory "+text_dir+" does not exist, will be unable to retrieve text for "+cluster_name);
+	    text_available = false;
+	    return true; // return true so that we still get the other services for the collection
+	}
+	// Get the default level out of <defaultLevel> (buildConfig.xml)
+ 	Element def = (Element) GSXML.getChildByTagName(info, DEFAULT_LEVEL_ELEM);
+ 	if (def != null) {
+	    this.default_level = def.getAttribute(GSXML.SHORTNAME_ATT);
+	}
+	if (this.default_level == null || this.default_level.equals("")) {
+	    logger.error("Default level not specified for "+this.cluster_name+", assuming "+DOC_LEVEL);
+	    this.default_level = DOC_LEVEL;
+ 	}
+	
+	return true;
+	
+    }
+    
+    /** returns the content of a node
+     * should return a nodeContent element:
+     * <nodeContent>text content or other elements</nodeContent>
+     */
+    protected Element getNodeContent(String doc_id, String lang) throws GSException {	
+	String doc_content = getTextString("TextRetrievalError", lang);
+	try {
+	    if (!text_available) {
+		throw new Exception("No text directory available");
+	    }
+	    
+	    long doc_num = this.gdbm_src.OID2Docnum(doc_id);
+	    if (doc_num == -1) {
+		throw new Exception("OID "+doc_id +" couldn't be converted to lucene doc num");
+	    }
+	
+	    DBInfo info=this.gdbm_src.getInfo(OID.getTop(doc_id));
+	    if (info == null) {
+		throw new Exception("Couldn't get GDBM database entry for "+OID.getTop(doc_id));
+	    }
+	    
+	    String archivedir=info.getInfo("archivedir");
+	    File doc_xml_file = new File(text_dir+archivedir+File.separatorChar+"doc.xml");
+	    if (!doc_xml_file.isFile()) {
+		throw new Exception("Doc XML file "+doc_xml_file.getPath()+" does not exist");
+	    }
+	    Document doc_xml_doc = this.converter.getDOM(doc_xml_file);
+	    if (doc_xml_doc == null) {
+		throw new Exception("Couldn't parse file "+doc_xml_file.getPath());
+	    }
+	    Element full_document = doc_xml_doc.getDocumentElement();
+	    if (full_document == null) {
+		throw new Exception("Couldn't parse file "+doc_xml_file.getPath());
+	    }
+	    Element current_section = null;
+	    if (default_level.equals(DOC_LEVEL)) {
+		current_section = full_document;
+	    } else {
+		current_section = GSXML.getNamedElement(full_document, SEC_LEVEL, ID_ATT, String.valueOf(doc_num));
+	    }
+	    if (current_section == null) {
+		throw new Exception("Couldn't find section "+ doc_num+" in file "+doc_xml_file.getPath());
+	    }
+	    doc_content = GSXML.getNodeText(current_section);
+	    if (doc_content == null) {
+		doc_content = "";
+	    } else {
+ 		doc_content = resolveTextMacros(doc_content, doc_id, lang);
+ 	    } 
+	} catch (Exception e) {
+	    logger.error("Error trying to get document text for "+doc_id+" in collection "+this.cluster_name+": "+e);
+	}
+	
+	Element content_node = this.doc.createElement(GSXML.NODE_CONTENT_ELEM);
+	Text t = this.doc.createTextNode(doc_content);
+	content_node.appendChild(t);
+	return content_node;
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2LuceneSearch.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2LuceneSearch.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2LuceneSearch.java	(revision 14125)
@@ -0,0 +1,290 @@
+/*
+ *    GS2LuceneSearch.java
+ *    Copyright (C) 2006 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *   the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.service;
+
+// Greenstone classes
+import org.greenstone.gsdl3.util.*;
+
+// XML classes
+import org.w3c.dom.Element; 
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Document; 
+// java classes
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.io.File;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Map;
+import java.util.Vector;
+
+// Logging
+import org.apache.log4j.Logger;
+
+import org.greenstone.LuceneWrapper.GS2LuceneQuery;
+import org.greenstone.LuceneWrapper.LuceneQueryResult;
+
+public class GS2LuceneSearch
+    extends AbstractGS2FieldSearch
+{
+    protected static final String RANK_PARAM_RANK_VALUE = "rank";
+
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.GS2LuceneSearch.class.getName());
+
+    private GS2LuceneQuery lucene_src=null;    
+    
+    public GS2LuceneSearch()
+    {
+	this.lucene_src = new GS2LuceneQuery();
+	// Lucene uses double operators, not single
+	AND_OPERATOR = "&&";
+	OR_OPERATOR = "||";
+
+	does_paging = true;
+	does_chunking = true;
+    }
+    
+    public void cleanUp() {
+	super.cleanUp();
+	this.lucene_src.cleanUp();
+    }
+    
+    /** configure this service */
+    public boolean configure(Element info, Element extra_info)
+    {
+	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+	
+	// Lucene doesn't do case folding or stemming or accent folding at the 
+	// moment
+	does_case = false;
+	does_stem = false;
+	does_accent = false;
+
+	return true;
+    }
+    
+    /** add in the lucene specific params to TextQuery */
+    protected void addCustomQueryParams(Element param_list, String lang) 
+    {
+	super.addCustomQueryParams(param_list, lang);
+	/** lucenes rank param is based on index fields, not ranked/not */
+	createParameter(RANK_PARAM, param_list, lang);
+
+    }
+    
+    /** create a param and add to the list */
+    /** we override this to do a special rank param */
+    protected void createParameter(String name, Element param_list, String lang) 
+    {
+	Element param = null;
+	if (name.equals(RANK_PARAM)) {
+	    // get the fields
+	    ArrayList fields = new ArrayList();
+	    fields.add(RANK_PARAM_RANK_VALUE);
+	    ArrayList field_names = new ArrayList();
+	    field_names.add(getTextString("param.sortBy.rank", lang)); 
+	    getSortByIndexData(fields, field_names, lang);
+	    
+	    param = GSXML.createParameterDescription2(this.doc, name, getTextString("param."+name, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, (String)fields.get(0), fields, field_names );
+	}
+	if (param != null) {
+	    param_list.appendChild(param);
+	} else {
+	    super.createParameter(name, param_list, lang);
+	}
+    }
+    
+    protected void getSortByIndexData(ArrayList index_ids, ArrayList index_names, String lang) {
+	// the index info -
+	Element index_list = (Element)GSXML.getChildByTagName(this.config_info, INDEX_ELEM+GSXML.LIST_MODIFIER);
+	NodeList indexes = index_list.getElementsByTagName(INDEX_ELEM);
+	int len = indexes.getLength();
+	// now add even if there is only one
+	for (int i=0; i<len; i++) {
+	    Element index = (Element)indexes.item(i);
+	    String shortname = index.getAttribute(GSXML.SHORTNAME_ATT);
+	    if (shortname.equals("") || shortname.equals("ZZ") || shortname.equals("TX")) {
+		continue;
+	    }
+	    index_ids.add("by"+shortname);
+	    String display_name = GSXML.getDisplayText(index, GSXML.DISPLAY_TEXT_NAME, lang, "en");
+	    if (display_name.equals("")) {
+		display_name = index.getAttribute(GSXML.NAME_ATT);
+		if (display_name.equals("")) {
+		    display_name = shortname;
+		}
+	    }
+	    index_names.add(display_name);
+		
+	}
+	
+    }
+
+    /** methods to handle actually doing the query */
+
+    /** do any initialisation of the query object */
+    protected boolean setUpQueryer(HashMap params) {
+       	String indexdir = GSFile.collectionBaseDir(this.site_home, this.cluster_name) + File.separatorChar + "index"+File.separatorChar;
+	
+	String index = "didx";
+	String physical_index_language_name=null;
+	String physical_sub_index_name=null;
+	int maxdocs = 100;
+	int hits_per_page = 20;
+	int start_page = 1;
+	// set up the query params
+    	Set entries = params.entrySet();
+    	Iterator i = entries.iterator();
+    	while (i.hasNext()) {
+    	    Map.Entry m = (Map.Entry)i.next();
+    	    String name = (String)m.getKey();
+    	    String value = (String)m.getValue();
+    	    
+    	    if (name.equals(MAXDOCS_PARAM)&& !value.equals("")) {
+		maxdocs = Integer.parseInt(value);
+	    } else if (name.equals(HITS_PER_PAGE_PARAM)) {
+		hits_per_page = Integer.parseInt(value);
+	    } else if (name.equals(START_PAGE_PARAM)) {
+		start_page = Integer.parseInt(value);
+		
+    	    } else if (name.equals(MATCH_PARAM)) {
+    		if (value.equals(MATCH_PARAM_ALL)) {
+		    this.lucene_src.setDefaultConjunctionOperator("AND");
+    		} else{
+		    this.lucene_src.setDefaultConjunctionOperator("OR");
+    		}
+    	    } else if (name.equals(RANK_PARAM)) {
+		if (value.equals(RANK_PARAM_RANK_VALUE)) {
+		    value = null;
+		}
+		this.lucene_src.setSortField(value);
+    	    } else if (name.equals(LEVEL_PARAM)) {
+		if (value.toUpperCase().equals("SEC")){
+		    index = "sidx";
+		}
+		else {
+		    index = "didx";
+		}
+	    } else if (name.equals(INDEX_SUBCOLLECTION_PARAM)) {
+		physical_sub_index_name=value;
+	    } else if (name.equals(INDEX_LANGUAGE_PARAM)){
+		physical_index_language_name=value;
+	    }  // ignore any others
+    	}
+	// set up start and end results if necessary
+	int start_results = 1;
+	if (start_page != 1) {
+	    start_results = ((start_page-1) * hits_per_page) + 1;
+	}
+	int end_results = hits_per_page * start_page;
+	this.lucene_src.setStartResults(start_results);
+	this.lucene_src.setEndResults(end_results);
+	
+
+	if (index.equals("sidx") || index.equals("didx")){
+	    if (physical_sub_index_name!=null) {
+		index+=physical_sub_index_name;
+	    }   
+	    if (physical_index_language_name!=null){
+		index+=physical_index_language_name;
+	    }
+	}
+
+	this.lucene_src.setIndexDir(indexdir+index);
+	this.lucene_src.initialise();
+	return true;
+    }
+    /** do the query */
+    protected Object runQuery(String query) {
+	try {
+	    LuceneQueryResult lqr=this.lucene_src.runQuery(query);
+	    return lqr;
+	} catch (Exception e) {
+	    logger.error ("exception happened in run query: ", e);
+	}
+	
+	return null;
+    }
+    /** get the total number of docs that match */
+    protected long numDocsMatched(Object query_result) {
+    	return ((LuceneQueryResult)query_result).getTotalDocs();
+    	
+    }
+    /** get the list of doc ids */
+    protected String [] getDocIDs(Object query_result) {
+    	Vector docs = ((LuceneQueryResult)query_result).getDocs();
+    	String [] doc_nums = new String [docs.size()];
+    	for (int d = 0; d < docs.size(); d++) {
+	    String doc_num = Long.toString(((LuceneQueryResult.DocInfo) docs.elementAt(d)).num_);
+    	    doc_nums[d] = doc_num;
+    	}
+    	return doc_nums;
+    }
+    /** get the list of doc ranks */
+    protected String [] getDocRanks(Object query_result) {
+    	Vector docs = ((LuceneQueryResult)query_result).getDocs();
+    	String [] doc_ranks = new String [docs.size()];
+    	for (int d = 0; d < docs.size(); d++) {
+    	    doc_ranks[d] = Float.toString(((LuceneQueryResult.DocInfo) docs.elementAt(d)).rank_);
+    	}
+    	return doc_ranks;
+    }
+    /** add in term info if available */
+    protected boolean addTermInfo(Element term_list, HashMap params,
+				  Object query_result) {
+    	String query_level = (String)params.get(LEVEL_PARAM); // the current query level
+	
+    	Vector terms = ((LuceneQueryResult)query_result).getTerms();
+    	for (int t = 0; t < terms.size(); t++) {
+    	    LuceneQueryResult.TermInfo term_info = (LuceneQueryResult.TermInfo) terms.get(t);
+    	    
+    	    Element term_elem = this.doc.createElement(GSXML.TERM_ELEM);
+    	    term_elem.setAttribute(GSXML.NAME_ATT, term_info.term_);
+    	    term_elem.setAttribute(FREQ_ATT, "" + term_info.term_freq_);
+    	    term_elem.setAttribute(NUM_DOCS_MATCH_ATT, "" + term_info.match_docs_);
+   	    term_elem.setAttribute(FIELD_ATT, term_info.field_);
+    	    term_list.appendChild(term_elem);
+    	}
+    	return true;
+    }
+    
+    protected String addFieldInfo(String query, String field) {
+	if (field.equals("") || field.equals("ZZ")) {
+	    return query;
+	}
+	return field+":("+query+")";
+    }
+    
+    protected void addQueryElem(StringBuffer s, String q, String f, String c) {
+	
+	String combine="";
+	if (s.length()>0) {
+	    combine = " "+c+" ";
+	}
+	s.append(combine + addFieldInfo(q,f));
+    }
+    
+    /** Lucene doesn't use these options at the moment */
+    protected String addStemOptions(String query, String stem,
+				    String casef, String accent) {
+	return query;
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2MGPPRetrieve.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2MGPPRetrieve.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2MGPPRetrieve.java	(revision 14125)
@@ -0,0 +1,122 @@
+/*
+ *    GS2MGPPRetrieve.java
+ *    Copyright (C) 2005 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.service;
+
+// Greenstone classes
+import org.greenstone.mgpp.*;
+import org.greenstone.gsdl3.core.GSException;
+import org.greenstone.gsdl3.util.GSFile;
+import org.greenstone.gsdl3.util.GSXML;
+
+// XML classes
+import org.w3c.dom.Element;
+import org.w3c.dom.Text;
+
+// General Java classes
+import java.io.File;
+
+import org.apache.log4j.*;
+
+public class GS2MGPPRetrieve
+    extends AbstractGS2DocumentRetrieve
+{
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.GS2MGPPRetrieve.class.getName());
+
+     // Parameters used
+    private static final String LEVEL_PARAM = "level";
+
+    // Elements used in the config file that are specific to this class
+    private static final String DEFAULT_LEVEL_ELEM = "defaultLevel";
+
+    private MGPPWrapper mgpp_src = null;
+    
+    private String default_level = null;
+    private String mgpp_textdir = null;
+	
+    public GS2MGPPRetrieve() {
+	this.mgpp_src = new MGPPWrapper();
+    }
+
+    public void cleanUp() {
+	super.cleanUp();
+	this.mgpp_src.unloadIndexData();
+    }
+
+    /** configure this service */
+    public boolean configure(Element info, Element extra_info)
+    {
+	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+
+	// Do specific configuration
+	logger.info("Configuring GS2MGPPRetrieve...");
+
+	// Get the default level out of <defaultLevel> (buildConfig.xml)
+	Element def = (Element) GSXML.getChildByTagName(info, DEFAULT_LEVEL_ELEM);
+	if (def != null) {
+	    this.default_level = def.getAttribute(GSXML.SHORTNAME_ATT);
+	}
+	if (this.default_level == null || this.default_level.equals("")) {
+	    logger.error("default level not specified!");
+	    return false;
+	}
+	
+	// The location of the MGPP text files
+	mgpp_textdir = GSFile.collectionBaseDir(this.site_home, this.cluster_name) +
+	    File.separatorChar + GSFile.collectionTextPath(this.index_stem);
+
+	// Do generic configuration
+	return true;
+ 
+    }
+    
+    /** returns the content of a node
+     * should return a nodeContent element:
+     * <nodeContent>text content or other elements</nodeContent>
+     */
+    protected Element getNodeContent(String doc_id, String lang) throws GSException {
+	long doc_num = this.gdbm_src.OID2Docnum(doc_id);
+	if (doc_num == -1) {
+	    logger.error("OID "+doc_id +" couldn't be converted to mgpp num");
+	    return null;
+	}
+	Element content_node = this.doc.createElement(GSXML.NODE_CONTENT_ELEM);
+	
+	String doc_content = "";
+	try {
+	    doc_content = this.mgpp_src.getDocument(this.mgpp_textdir, 
+						    this.default_level,
+						    doc_num);
+	    if (doc_content != null) {
+		doc_content = resolveTextMacros(doc_content, doc_id, lang);
+	    } 
+	} catch (Exception e) {
+	    logger.info("exception happended with mgpp_src.getDocument()" + e);
+	    doc_content = "this is the content for section hash id "+ doc_id+", mgpp doc num "+doc_num+"\n";
+
+	}
+	Text t = this.doc.createTextNode(doc_content);
+	content_node.appendChild(t);
+	return content_node;
+
+    }
+
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2MGPPSearch.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2MGPPSearch.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2MGPPSearch.java	(revision 14125)
@@ -0,0 +1,281 @@
+/*
+ *    GS2MGPPSearch.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *   the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.service;
+
+
+// Greenstone classes
+import org.greenstone.mgpp.*;
+import org.greenstone.gsdl3.util.*;
+
+// XML classes
+import org.w3c.dom.Document;
+import org.w3c.dom.Element; 
+import org.w3c.dom.NodeList;
+
+// java classes
+import java.util.Iterator;
+import java.util.Set;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ArrayList;
+import java.util.Vector;
+import java.io.File;
+
+import org.apache.log4j.*;
+
+/**
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @author <a href="mailto:mdewsnip@cs.waikato.ac.nz">Michael Dewsnip</a>
+ */
+
+public class GS2MGPPSearch 
+    extends AbstractGS2FieldSearch 
+{
+    private MGPPWrapper mgpp_src=null;
+
+    private String physical_index_name = "idx";
+    
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.GS2MGPPSearch.class.getName());
+
+    /** constructor */
+    public GS2MGPPSearch()
+    {
+	this.mgpp_src = new MGPPWrapper();
+    }
+
+    public void cleanUp() {
+	super.cleanUp();
+	this.mgpp_src.unloadIndexData();
+    }
+
+    /** configure this service */
+    public boolean configure(Element info, Element extra_info)
+    {
+	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+
+	// the default level is also the level which gdbm is expecting
+	// this must not be overwritten
+	this.mgpp_src.setReturnLevel(this.default_gdbm_level);
+	// return term info
+	this.mgpp_src.setReturnTerms(true);
+	// set the default - this may be overwritten by query params
+	this.mgpp_src.setQueryLevel(this.default_level);
+	this.mgpp_src.setMaxNumeric(this.maxnumeric);
+    
+	return true;
+    }
+
+    /** add in the mgpp specific params to TextQuery */
+    protected void addCustomQueryParams(Element param_list, String lang) 
+    {
+	super.addCustomQueryParams(param_list, lang);
+	createParameter(RANK_PARAM, param_list, lang);
+    }
+
+    protected boolean setUpQueryer(HashMap params) {
+
+	// set up the query params
+	Set entries = params.entrySet();
+	Iterator i = entries.iterator();
+	String physical_sub_index_name=null;
+	String physical_index_language_name=null;
+	while (i.hasNext()) {
+	    Map.Entry m = (Map.Entry)i.next();
+	    String name = (String)m.getKey();
+	    String value = (String)m.getValue();
+	    
+	    if (name.equals(CASE_PARAM)) {
+		boolean val = (value.equals(BOOLEAN_PARAM_ON)?true:false);
+		this.mgpp_src.setCase(val);		
+	    } else if (name.equals(STEM_PARAM)) {
+		boolean val = (value.equals(BOOLEAN_PARAM_ON)?true:false);
+		this.mgpp_src.setStem(val);
+	    } else if (name.equals(ACCENT_PARAM)) {
+		boolean val = (value.equals(BOOLEAN_PARAM_ON)?true:false);
+		this.mgpp_src.setAccentFold(val);
+	    } else if (name.equals(MAXDOCS_PARAM)&& !value.equals("")) {
+		int docs = Integer.parseInt(value);
+		this.mgpp_src.setMaxDocs(docs);
+	    } else if (name.equals(LEVEL_PARAM)) {
+		this.mgpp_src.setQueryLevel(value);
+	    } else if (name.equals(MATCH_PARAM)) {
+		int mode;
+		if (value.equals(MATCH_PARAM_ALL)) mode=1;
+		else mode=0;
+		this.mgpp_src.setMatchMode(mode);
+	    } else if (name.equals(RANK_PARAM)) {
+		if (value.equals(RANK_PARAM_RANK)) {
+		    this.mgpp_src.setSortByRank(true);
+		} else if (value.equals(RANK_PARAM_NONE)) {
+		    this.mgpp_src.setSortByRank(false);
+		}
+	    } else if (name.equals(INDEX_SUBCOLLECTION_PARAM)) {
+		physical_sub_index_name=value;
+	    }else if (name.equals(INDEX_LANGUAGE_PARAM)){
+		physical_index_language_name=value;
+	    } // ignore any others
+	}
+	
+	if (physical_index_name.equals("idx")){
+	    if (physical_sub_index_name!=null) {
+		physical_index_name+=physical_sub_index_name;
+	    }   
+	    if (physical_index_language_name!=null){
+		physical_index_name+=physical_index_language_name;
+	    }
+	}
+
+	// set up mgpp_src
+	String indexdir = GSFile.collectionBaseDir(this.site_home, this.cluster_name) + File.separatorChar + GSFile.collectionIndexPath(this.index_stem, physical_index_name);
+	this.mgpp_src.loadIndexData(indexdir);
+
+	physical_index_name="idx";
+	return true;
+    }
+    
+    protected Object runQuery(String query) {
+	this.mgpp_src.runQuery(query);
+	MGPPQueryResult mqr= this.mgpp_src.getQueryResult();
+	return mqr;
+
+    }
+
+    protected long numDocsMatched(Object query_result) {
+	return ((MGPPQueryResult)query_result).getTotalDocs();
+    }
+    
+    protected String [] getDocIDs(Object query_result) {
+	
+	Vector docs = ((MGPPQueryResult)query_result).getDocs();
+	String [] doc_nums = new String [docs.size()];
+	for (int d = 0; d < docs.size(); d++) {
+	    doc_nums[d] = Long.toString((((MGPPDocInfo) docs.elementAt(d)).num_));
+	}
+	return doc_nums;
+    }
+    
+    protected String [] getDocRanks(Object query_result) {
+	
+	Vector docs = ((MGPPQueryResult)query_result).getDocs();
+	String [] doc_ranks = new String [docs.size()];
+	for (int d = 0; d < docs.size(); d++) {
+	    doc_ranks[d] = Float.toString(((MGPPDocInfo) docs.elementAt(d)).rank_);
+	}
+	return doc_ranks;
+    }
+    
+    protected boolean addTermInfo(Element term_list, HashMap params, 
+				  Object query_result) {
+
+	String query_level = (String)params.get(LEVEL_PARAM); // the current query level
+
+	Vector terms = ((MGPPQueryResult)query_result).getTerms();
+	for (int t = 0; t < terms.size(); t++) {
+	    MGPPTermInfo term_info = (MGPPTermInfo) terms.get(t);
+	    
+	    Element term_elem = this.doc.createElement(GSXML.TERM_ELEM);
+	    term_elem.setAttribute(GSXML.NAME_ATT, term_info.term_);
+	    term_elem.setAttribute(STEM_ATT, "" + term_info.stem_method_);
+	    term_elem.setAttribute(FREQ_ATT, "" + term_info.term_freq_);
+	    term_elem.setAttribute(NUM_DOCS_MATCH_ATT, "" + term_info.match_docs_);
+	    String field = term_info.tag_;
+	    if (field.equals(query_level)) {
+		// ignore
+		field = "";
+	    }
+	    term_elem.setAttribute(FIELD_ATT, field);
+	    
+	    Vector equiv_terms = term_info.equiv_terms_;
+	    Element equiv_term_list = this.doc.createElement(EQUIV_TERM_ELEM+GSXML.LIST_MODIFIER);
+	    term_elem.appendChild(equiv_term_list);
+	    
+	    for (int et = 0; et < equiv_terms.size(); et++) {
+		String equiv_term = (String) equiv_terms.get(et);
+
+		Element equiv_term_elem = this.doc.createElement(GSXML.TERM_ELEM);
+		equiv_term_elem.setAttribute(GSXML.NAME_ATT, equiv_term);
+		equiv_term_elem.setAttribute(NUM_DOCS_MATCH_ATT, "");
+		equiv_term_elem.setAttribute(FREQ_ATT, "");
+		equiv_term_list.appendChild(equiv_term_elem);
+	    }
+
+	    term_list.appendChild(term_elem);
+	}
+	return true;
+    }
+    
+
+    protected String addFieldInfo(String query, String field) {
+	if (field.equals("") || field.equals("ZZ")) {
+	    return query;
+	}
+	return "["+query+"]:"+field;
+    }
+    protected void addQueryElem(StringBuffer final_query, String query, 
+				String field, String combine) {
+
+	String comb="";
+	if (final_query.length()>0) {
+	    comb = " "+combine+" ";
+	}
+	final_query.append(comb+addFieldInfo(query,field));
+    }
+    
+    protected String addStemOptions(String query, String stem,
+				    String casef, String accent) {
+	String mods = "#";
+	if (casef != null) {
+	    if (casef.equals("1")) {
+		mods += "i";
+	    } else {
+		mods += "c";
+	    }
+	}
+	if (stem != null) {
+	    if (stem.equals("1")) {
+		mods += "s";
+	    } else {
+		mods+= "u";
+	    }
+	}
+	if (accent != null) {
+	    if (accent.equals("1")) {
+		mods += "f";
+	    } else {
+		mods += "a";
+	    }
+	}
+	
+	StringBuffer temp = new StringBuffer();
+	String [] terms = query.split(" ");
+	for (int i=0; i<terms.length; i++) {
+	    String t = terms[i].trim();
+	    // what is the TX bit about???
+	    if (!t.equals("") && !t.equals("TX")) {
+		temp.append(" "+t+mods);
+	    }
+	}
+	return temp.toString();
+    }
+
+}
+
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2MGRetrieve.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2MGRetrieve.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2MGRetrieve.java	(revision 14125)
@@ -0,0 +1,148 @@
+/*
+ *    GS2MGRetrieve.java
+ *    Copyright (C) 2005 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.service;
+
+// Greenstone classes
+import org.greenstone.mg.*;
+import org.greenstone.gsdl3.core.GSException;
+import org.greenstone.gsdl3.util.GSFile;
+import org.greenstone.gsdl3.util.GSXML;
+
+// XML classes
+import org.w3c.dom.Element;
+import org.w3c.dom.Text;
+
+// General Java classes
+import java.io.File;
+
+import org.apache.log4j.*;
+
+public class GS2MGRetrieve
+    extends AbstractGS2DocumentRetrieve
+{
+   static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.GS2MGRetrieve.class.getName());
+
+    // Elements used in the config file that are specific to this class
+    private static final String DEFAULT_INDEX_ELEM = "defaultIndex";
+    private static final String INDEX_LIST_ELEM = "indexList";
+    private static final String INDEX_ELEM = "index";
+    private static final String DEFAULT_INDEX_SUBCOLLECTION_ELEM = "defaultIndexSubcollection";
+    private static final String DEFAULT_INDEX_LANGUAGE_ELEM = "defaultIndexLanguage";
+  
+    private MGWrapper mg_src = null;
+    private String mg_basedir = null;
+    private String mg_textdir = null;
+    private String default_index = null;
+    private boolean has_default_index = false;
+	
+    public GS2MGRetrieve() {
+	this.mg_src = new MGWrapper();
+    }
+
+    public void cleanUp() {
+	super.cleanUp();
+	this.mg_src.unloadIndexData();
+    }
+
+    /** configure this service */
+    public boolean configure(Element info, Element extra_info)
+    {
+	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+	
+	// Do specific configuration
+	logger.info("Configuring GS2MGRetrieve...");
+	
+	// Get the default index out of <defaultIndex> (buildConfig.xml)
+	Element def = (Element) GSXML.getChildByTagName(info, DEFAULT_INDEX_ELEM);
+	if (def != null) {
+	    this.default_index = def.getAttribute(GSXML.SHORTNAME_ATT);
+	}
+         Element defSub = (Element) GSXML.getChildByTagName(info, DEFAULT_INDEX_SUBCOLLECTION_ELEM); 
+	if (defSub != null) {
+	    this.default_index += defSub.getAttribute(GSXML.SHORTNAME_ATT);
+	    logger.info("default indexSubcollection is "+defSub.getAttribute(GSXML.SHORTNAME_ATT));      
+	} //concate defaultIndex + defaultIndexSubcollection
+
+	//get the default indexLanguage out of <defaultIndexLanguage> (buildConfig.xml)
+        Element defLang = (Element) GSXML.getChildByTagName(info, DEFAULT_INDEX_LANGUAGE_ELEM); 
+	if (defLang != null) {
+	    this.default_index += defLang.getAttribute(GSXML.SHORTNAME_ATT);
+            logger.info("default indexLanguage is "+defLang.getAttribute(GSXML.SHORTNAME_ATT)); 
+	} //concate defaultIndex + defaultIndexSubcollection + defaultIndexLanguage
+     
+
+	if (this.default_index == null || this.default_index.equals("")) {
+             logger.error("default index is not specified, the content of a document will not be retrieved");
+              has_default_index = false;
+	      return true;
+	    //}
+	}
+	logger.debug("Default index: " + this.default_index);
+       
+	// The location of the MG index and text files
+	mg_basedir = GSFile.collectionBaseDir(this.site_home, this.cluster_name) + File.separatorChar;  // Needed by MG
+	mg_textdir = GSFile.collectionTextPath(this.index_stem);
+	// index is only needed to start up MG, not used so just use the default index
+	String indexpath = GSFile.collectionIndexPath(this.index_stem, this.default_index);
+	this.mg_src.setIndex(indexpath);
+	has_default_index = true;
+	return true;
+    }
+    
+    /** returns the content of a node
+     * should return a nodeContent element:
+     * <nodeContent>text content or other elements</nodeContent>
+     */
+    protected Element getNodeContent(String doc_id, String lang) throws GSException {
+	long doc_num = this.gdbm_src.OID2Docnum(doc_id);
+	if (doc_num == -1) {
+	    logger.error("OID "+doc_id +" couldn't be converted to mg num");
+	    return null;
+	}
+	Element content_node = this.doc.createElement(GSXML.NODE_CONTENT_ELEM);
+	
+         
+	String doc_content = null;
+
+        //means that this.mg_src is up and running  
+	if (has_default_index ){
+            doc_content =  this.mg_src.getDocument(this.mg_basedir,
+				  	     this.mg_textdir, doc_num);
+	}
+ 
+	if (doc_content!=null) {
+	    // remove any ctrl-c or ctrl-b 
+	    doc_content = doc_content.replaceAll("\u0002|\u0003", "");
+	    // replace _httpimg_ with the correct address
+	    doc_content = resolveTextMacros(doc_content, doc_id, lang);
+	    //GSXML.addDocText(this.doc, doc, doc_content);
+	} else {
+	    logger.error("the doc content was null, not getting that section\n");
+	    doc_content = "couldn't retrieve content for this section, please check the log file for more detail\n";
+	}
+	Text t = this.doc.createTextNode(doc_content);
+	content_node.appendChild(t);
+	return content_node;
+
+    }
+
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2MGSearch.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2MGSearch.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GS2MGSearch.java	(revision 14125)
@@ -0,0 +1,253 @@
+/*
+ *    GS2MGSearch.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *   the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.service;
+
+
+// Greenstone classes
+import org.greenstone.mg.*;
+import org.greenstone.gsdl3.util.*;
+
+// XML classes
+import org.w3c.dom.Document;
+import org.w3c.dom.Element; 
+import org.w3c.dom.NodeList;
+
+// java
+import java.util.Vector;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.Iterator;
+import java.io.File;
+
+import org.apache.log4j.*;
+
+/**
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @author <a href="mailto:mdewsnip@cs.waikato.ac.nz">Michael Dewsnip</a>
+ */
+
+public class GS2MGSearch 
+    extends AbstractGS2Search 
+{
+
+    protected MGWrapper mg_src = null;
+
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.GS2MGSearch.class.getName());
+
+
+    /** constructor */
+    public GS2MGSearch()
+    {
+	this.mg_src = new MGWrapper();
+	
+    }
+    public void cleanUp() {
+	super.cleanUp();
+	this.mg_src.unloadIndexData();
+    }
+
+    /** configure this service */
+    public boolean configure(Element info, Element extra_info)
+    {
+	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+
+	this.mg_src.setMaxNumeric(this.maxnumeric);             
+        	
+	return true;
+    }
+    
+
+
+    /** do the actual query */
+    protected Element processTextQuery(Element request) 
+    {
+
+	// Create a new (empty) result message
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.setAttribute(GSXML.FROM_ATT, TEXT_QUERY_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+
+	// Get the parameters of the request
+	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (param_list == null) {
+	    logger.error("TextQuery request had no paramList.");
+	    return result;  // Return the empty result
+	}
+
+	// Process the request parameters
+	HashMap params = GSXML.extractParams(param_list, false);
+	
+	// Make sure a query has been specified
+	String query = (String) params.get(QUERY_PARAM);
+	if (query == null || query.equals("")) {
+	    return result;  // Return the empty result
+	}
+
+	// If an index hasn't been specified, use the default
+	String index = (String) params.get(INDEX_PARAM); 
+	if (index == null) {
+	    index = this.default_index;
+	}
+
+	// If a subcollection index has been specified, use it
+	String indexSub = (String) params.get(INDEX_SUBCOLLECTION_PARAM); 
+	if (indexSub != null) {
+	    index += indexSub;
+	}
+	else{
+	    if (!this.default_index_subcollection.equals("")){
+		index += this.default_index_subcollection;
+	    }
+	}
+
+	// If a subcollection index has been specified, use it
+	String indexLang = (String) params.get(INDEX_LANGUAGE_PARAM); 
+	if (indexLang != null) {
+	    index += indexLang;
+	}
+	else{
+	    if (!this.default_index_language.equals("")){
+		index += this.default_index_language; 
+	    }
+	}
+   
+	// The location of the MG index and text files
+	String basedir = GSFile.collectionBaseDir(this.site_home, this.cluster_name) +  File.separatorChar;  // Needed for MG
+	String textdir = GSFile.collectionTextPath(this.index_stem);
+	String indexpath = GSFile.collectionIndexPath(this.index_stem, index);
+	this.mg_src.setIndex(indexpath);
+	System.err.println("index path = "+indexpath);
+	// set the mg query parameters to the values the user has specified
+	setStandardQueryParams(params);
+	this.mg_src.runQuery(basedir, textdir, query);
+	MGQueryResult mqr = this.mg_src.getQueryResult();
+	if (mqr.isClear()) {
+	    // something has gone wrong
+	    GSXML.addError(this.doc, result, "Couldn't query the mg database", GSXML.ERROR_TYPE_SYSTEM);
+	    return result;
+	}
+	long totalDocs = mqr.getTotalDocs();
+
+	// Get the docnums out, and convert to HASH ids
+	Vector docs = mqr.getDocs();
+	if (docs.size() == 0) {
+	    logger.error("No results found...\n");
+	}
+
+	// Create a metadata list to store information about the query results
+	Element metadata_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER); 
+	result.appendChild(metadata_list);
+
+	// Add a metadata element specifying the number of matching documents
+	// because teh total number is just the number returned, use numDocsReturned, not numDocsMatched
+	GSXML.addMetadata(this.doc, metadata_list, "numDocsReturned", ""+totalDocs);
+	// add a metadata item to specify what actual query was done - eg if stuff was stripped out etc. and then we can use the query later, cos we don't know which parameter was the query
+	GSXML.addMetadata(this.doc, metadata_list, "query", query);
+
+	if (docs.size() > 0) {
+	    // Create a document list to store the matching documents, and add them
+	    Element document_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	    result.appendChild(document_list);
+	    for (int d = 0; d < docs.size(); d++) {
+		long docnum = ((MGDocInfo) docs.elementAt(d)).num_;
+		float rank = ((MGDocInfo) docs.elementAt(d)).rank_;
+		String doc_id = internalNum2OID(docnum);
+		Element doc_node = createDocNode(doc_id, Float.toString(rank));
+		document_list.appendChild(doc_node);
+	    }
+	}
+	
+	// Create a term list to store the term information, and add it
+	Element term_list = this.doc.createElement(GSXML.TERM_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(term_list);
+	Vector terms = mqr.getTerms();
+	for (int t = 0; t < terms.size(); t++) {
+	    MGTermInfo term_info = (MGTermInfo) terms.get(t);
+
+	    String term = term_info.term_;
+	    int stem_method = term_info.stem_method_;
+	    Vector equiv_terms = term_info.equiv_terms_;
+
+	    Element term_elem = this.doc.createElement(GSXML.TERM_ELEM);
+	    term_elem.setAttribute(GSXML.NAME_ATT, term);
+	    term_elem.setAttribute(STEM_ATT, "" + stem_method);
+
+	    Element equiv_term_list = this.doc.createElement(EQUIV_TERM_ELEM+GSXML.LIST_MODIFIER);
+	    term_elem.appendChild(equiv_term_list);
+
+	    long total_term_freq = 0;
+	    for (int et = 0; et < equiv_terms.size(); et++) {
+		MGEquivTermInfo equiv_term_info = (MGEquivTermInfo) equiv_terms.get(et);
+
+		Element equiv_term_elem = this.doc.createElement(GSXML.TERM_ELEM);
+		equiv_term_elem.setAttribute(GSXML.NAME_ATT, equiv_term_info.term_);
+		equiv_term_elem.setAttribute(NUM_DOCS_MATCH_ATT, "" + equiv_term_info.match_docs_);
+		equiv_term_elem.setAttribute(FREQ_ATT, "" + equiv_term_info.term_freq_);
+		equiv_term_list.appendChild(equiv_term_elem);
+
+		total_term_freq += equiv_term_info.term_freq_;
+	    }
+
+	    term_elem.setAttribute(FREQ_ATT, "" + total_term_freq);
+	    term_list.appendChild(term_elem);
+	}
+	return result;
+    }
+
+    // should probably use a list rather than map
+    protected boolean setStandardQueryParams(HashMap params)
+    {
+	// set the default ones
+	this.mg_src.setReturnTerms(true);
+	this.mg_src.setCase(true); // turn casefolding on by default
+	Set entries = params.entrySet();
+	Iterator i = entries.iterator();
+	while (i.hasNext()) {
+	    Map.Entry m = (Map.Entry)i.next();
+	    String name = (String)m.getKey();
+	    String value = (String)m.getValue();
+
+	    if (name.equals(CASE_PARAM)) {
+		boolean val = (value.equals(BOOLEAN_PARAM_ON) ? true : false);
+		this.mg_src.setCase(val);
+	    }
+	    else if (name.equals(STEM_PARAM)) {
+		boolean val = (value.equals(BOOLEAN_PARAM_ON) ? true : false);
+		this.mg_src.setStem(val);
+	    }
+	    else if (name.equals(MATCH_PARAM)) {
+		int mode = (value.equals(MATCH_PARAM_ALL) ? 1 : 0);
+		this.mg_src.setMatchMode(mode);
+	    }
+	    else if (name.equals(MAXDOCS_PARAM)) {
+		int docs = Integer.parseInt(value);
+		this.mg_src.setMaxDocs(docs);
+	    } // ignore any others
+	}
+	return true;
+    }
+
+
+}
+
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GoogleSearch.java.tmp
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GoogleSearch.java.tmp	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GoogleSearch.java.tmp	(revision 14125)
@@ -0,0 +1,227 @@
+package org.greenstone.gsdl3.service;
+
+// Greenstone classes
+import org.greenstone.gsdl3.util.*;
+
+//Google Web Services API classes
+//import com.google.soap.search.GoogleSearch;
+import com.google.soap.search.GoogleSearchFault;
+import com.google.soap.search.GoogleSearchResult;
+import com.google.soap.search.GoogleSearchResultElement;
+import com.google.soap.search.GoogleSearchDirectoryCategory;
+
+// XML classes
+import org.w3c.dom.Element; 
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList; 
+
+//Java classes
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.io.File;
+import java.io.InputStream;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URLConnection;
+import java.net.URL;
+import java.net.Authenticator;
+import java.net.PasswordAuthentication;
+import java.net.MalformedURLException;
+import java.lang.Object;
+
+
+/**
+ *
+ * @author <a href="mailto:chi@cs.waikato.ac.nz">Chi-Yu Huang</a>
+ *
+ */
+
+public class GoogleSearch
+    extends AbstractSearch {
+    
+    //Parameters connect to Proxy Server
+    private boolean using_proxy = false;
+    private String proxy_host = null;
+    private int proxy_port;
+    private String proxy_user = null;
+    private char [] proxy_passwd = null;
+
+    // google key
+    private String client_key = null;
+    
+    public GoogleSearch()
+    {
+    }
+	    
+    //Configure GoogleSearch Service
+    public boolean configure(Element info, Element extra_info) 
+    { 
+	if (!super.configure(info, extra_info)) {
+	    return false;
+	}
+	System.err.println("Configuring GoogleSearch");
+	Element server_elem = (Element)GSXML.getChildByTagName(info, "googleServer");
+	if (server_elem == null) {
+	    System.err.println("GoogleSearch.configure error: no googleServer element found");
+	    return false;
+	}
+	
+	client_key = server_elem.getAttribute("key");
+	if (client_key.equals("")) {
+	    System.err.println("GoogleSearch.configure error: no client_key for the googleServer element");
+	    return false;
+	}
+	
+	does_paging = true;
+	does_chunking = false;
+
+	// are we behind a proxy??
+	// all the details should have been set up by the Message Router
+	proxy_host = System.getProperty("http.proxyHost");
+	if (proxy_host != null && !proxy_host.equals("")) {
+	    using_proxy = true;
+	    try {
+		proxy_port = Integer.parseInt(System.getProperty("http.proxyPort").trim());
+	    } catch (Exception e) {
+		System.err.println("GoogleSearch.configure error: couldn't get proxy port, defaulting to 80");
+		proxy_port = 80;
+	    }
+	    PasswordAuthentication pa = Authenticator.requestPasswordAuthentication(proxy_host, null, proxy_port, "http", "", null);
+	    proxy_user = pa.getUserName();
+	    proxy_passwd = pa.getPassword();
+	}
+	return true;
+    }
+    
+    /** Process a text query - implemented by concrete subclasses */
+    protected Element processTextQuery(Element request) {
+	
+	//Connect to Google Web API service
+	com.google.soap.search.GoogleSearch search = new com.google.soap.search.GoogleSearch();
+
+	// Set mandatory attributes
+	search.setKey(client_key);
+
+	// proxy??
+	if (using_proxy) {
+	    search.setProxyHost(proxy_host);
+	    search.setProxyPort(proxy_port);
+	    search.setProxyUserName(proxy_user);
+	    search.setProxyPassword(new String(proxy_passwd));
+	}
+
+	//set optional attributes
+	search.setSafeSearch(true);
+	
+	// Create a new (empty) result message
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.setAttribute(GSXML.FROM_ATT, TEXT_QUERY_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+	Element doc_node_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(doc_node_list);
+	Element query_metadata_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(query_metadata_list);
+
+	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (param_list == null) {
+	    System.err.println("GoogleSearch.processTextQuery Error:: TextQuery request had no paramList.");
+	    return result;  // Return the empty result
+	}
+
+	// Process the request parameters
+	HashMap params = GSXML.extractParams(param_list, false);
+
+	// Make sure a query has been specified
+	String query = (String) params.get(QUERY_PARAM);
+	if (query == null || query.equals("")) {
+	    System.err.println("GoogleSearch.processTextQuery Error: TextQuery request had no query string.");
+	    return result;  // Return the empty result
+	}
+       	// tidy whitespace
+	query = query.replaceAll("\\s+", "+");
+	
+	search.setQueryString(query);
+
+	//Check hits_per_page
+	int hits_per_page;
+	try {
+	    hits_per_page = Integer.parseInt(((String)params.get(HITS_PER_PAGE_PARAM)).trim());
+	} catch (Exception e) {
+	    System.err.println("GoogleSearch.processTextQuery error: couldn't get hits per page param, defaulting to 10");
+	    hits_per_page = 10;
+	}
+	//Check the start_page number
+	int start_page;
+	try {
+	    start_page = Integer.parseInt(((String) params.get(START_PAGE_PARAM)).trim());
+	} catch (Exception e) {
+	    System.err.println("GoogleSearch.processTextQuery error: couldn't get start page param, defaulting to 1");
+	    start_page = 1;
+	}
+	
+	//Invoke Actual Search
+	
+	// Google only allows 10 hits per request
+	int loop = hits_per_page/10;
+	int remainder = hits_per_page%10;
+	int google_start_page = (start_page-1)*hits_per_page;
+	int pages_per_loop;
+	for (int j=0; j < loop; j++){
+	    if (j < (loop-1) || remainder == 0) {
+		pages_per_loop = 10;
+	    } else {
+		pages_per_loop = remainder;
+	    }
+	    search.setMaxResults(pages_per_loop); 
+	    search.setStartResult(google_start_page);
+	    google_start_page = google_start_page + pages_per_loop;
+	    GoogleSearchResult google_result;
+	    try{
+		google_result = search.doSearch();
+	    } catch (GoogleSearchFault ex) {
+		System.err.println("GoogleSearch.processTextQuery error: the call to the Google Web APIs failed:" + ex.toString());
+		// add the error to the result
+		return result;
+	    }
+	    if (j==0) {
+		
+		//Total amount of documents Google Search returned
+		// only need to do this on the first loop
+		
+		long numdocs_matched = google_result.getEstimatedTotalResultsCount();	    
+		GSXML.addMetadata(this.doc, query_metadata_list, "numDocsMatched", ""+numdocs_matched);
+		
+	    }
+	    GoogleSearchResultElement[] details = google_result.getResultElements();
+	    for (int i=0; i<details.length; i++){
+		Element doc_node = this.doc.createElement(GSXML.DOC_NODE_ELEM);
+		doc_node_list.appendChild(doc_node);
+		
+		Element metadata_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+		doc_node.appendChild(metadata_list);
+		
+		String google_url = details[i].getURL();  
+		String google_title = details[i].getTitle();
+		String google_snippet = details[i].getSnippet();
+		if (google_url !=null) {
+		    GSXML.addMetadata(this.doc, metadata_list, "URL", google_url);
+		}
+		if (google_title != null) {
+		    GSXML.addMetadata(this.doc, metadata_list, "Title", google_title);
+		}
+		if (google_snippet != null) {
+		    GSXML.addMetadata(this.doc, metadata_list, "Snippet", google_snippet);
+		}
+	    }
+	} // for each loop
+	return result;
+    }
+    
+    protected void getIndexData(ArrayList index_ids, ArrayList index_names,String lang){
+       	index_ids.add("idx");
+	index_names.add("Google main index");
+    }
+    
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GutBookRetrieve.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GutBookRetrieve.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/GutBookRetrieve.java	(revision 14125)
@@ -0,0 +1,41 @@
+package org.greenstone.gsdl3.service;
+
+import org.greenstone.gsdl3.util.*;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+import org.w3c.dom.NodeList;
+
+public class GutBookRetrieve 
+    extends XMLRetrieve {
+
+    protected Element extractTitleMeta(Element section) {
+	Element meta_elem = this.doc.createElement(GSXML.METADATA_ELEM);
+	meta_elem.setAttribute(GSXML.NAME_ATT, "Title");
+
+	Element title_elem = (Element)GSXML.getChildByTagName(section, "title");
+	if (title_elem == null) {
+	    title_elem = (Element)GSXML.getNodeByPath(section, "chapheader/title");
+	}
+	if (title_elem == null) {
+	    // find teh first title elem
+	    NodeList titles = section.getElementsByTagName("title");
+	    if (titles != null) {
+		title_elem = (Element)titles.item(0);
+	    }
+	}
+
+	if (title_elem == null) {
+	    return null; // no title found
+	}
+	
+	
+	Text t = (Text) GSXML.getNodeTextNode(title_elem);
+	
+	meta_elem.appendChild(this.doc.importNode(t, false));
+	return meta_elem;
+
+    }
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/IViaProxy.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/IViaProxy.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/IViaProxy.java	(revision 14125)
@@ -0,0 +1,508 @@
+package org.greenstone.gsdl3.service;
+
+// Greenstone classes
+import org.greenstone.gsdl3.util.*;
+
+// XML classes
+import org.w3c.dom.Element; 
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList; 
+
+import java.util.HashMap;
+import java.io.File;
+import java.io.InputStream;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URLConnection;
+import java.net.URL;
+import java.net.Authenticator;
+import java.net.MalformedURLException;
+
+import org.apache.log4j.*;
+
+/**
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @version $Revision$
+ */
+
+public class IViaProxy 
+    extends ServiceRack {
+   
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.IViaProxy.class.getName());
+    
+    // the services on offer
+    // these strings must match what is found in the properties file
+    protected static final String TEXT_QUERY_SERVICE = "TextQuery";
+    protected static final String DOC_CONTENT_SERVICE = "DocumentContentRetrieve";
+    protected static final String DOC_META_SERVICE = "DocumentMetadataRetrieve";
+    protected static final String QUERY_PARAM = "query";
+    protected static final String FIELD_PARAM = "fields";
+    // have standard gs param names for hits per page, and start page
+    // these need to be mapped to iVia params
+    protected static final String GS_HITS_PARAM = "hitsPerPage";
+    protected static final String IM_HITS_PARAM = "no_of_records_per_page";
+    protected static final String GS_START_PAGE_PARAM = "startPage";
+    protected static final String IM_START_PAGE_PARAM = "start_page_no";
+
+    protected String ivia_server_url = null;
+    
+    public boolean configure(Element info, Element extra_info) {
+	
+	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+
+	Element server_elem = (Element)GSXML.getChildByTagName(info, "iViaServer");
+	if (server_elem == null) {
+	    logger.error("no iViaServer element found");
+	    return false;
+	}
+	ivia_server_url = server_elem.getAttribute("url");
+	if (ivia_server_url.equals("")) {
+	    logger.error("no url for the iViaServer element");
+	    return false;
+	}
+	Element tq_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	tq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
+	tq_service.setAttribute(GSXML.NAME_ATT, TEXT_QUERY_SERVICE);
+	this.short_service_info.appendChild(tq_service);
+
+	Element dc_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	dc_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
+	dc_service.setAttribute(GSXML.NAME_ATT, DOC_CONTENT_SERVICE);
+	this.short_service_info.appendChild(dc_service);
+
+	Element dm_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	dm_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
+	dm_service.setAttribute(GSXML.NAME_ATT, DOC_META_SERVICE);
+	this.short_service_info.appendChild(dm_service);
+	
+	// 
+	// add some format info to service map if there is any
+	String path = GSPath.appendLink(GSXML.SEARCH_ELEM, GSXML.FORMAT_ELEM);
+	Element format = (Element) GSXML.getNodeByPath(extra_info, path);
+	if (format != null) {
+	    this.format_info_map.put(TEXT_QUERY_SERVICE, this.doc.importNode(format, true));
+	}
+
+	
+	// look for document display format
+	path = GSPath.appendLink(GSXML.DISPLAY_ELEM, GSXML.FORMAT_ELEM);
+	Element display_format = (Element)GSXML.getNodeByPath(extra_info, path);
+	if (display_format != null) {
+	    this.format_info_map.put(DOC_CONTENT_SERVICE, this.doc.importNode(display_format, true));
+	    // shoudl we make a copy?
+	}
+
+	return true;
+	
+    }
+    
+    protected Element getServiceDescription(String service, String lang, String subset) {
+	
+	if (service.equals(TEXT_QUERY_SERVICE)) {
+	    Element tq_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    tq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
+	    tq_service.setAttribute(GSXML.NAME_ATT, TEXT_QUERY_SERVICE);
+	    if (subset == null || subset.equals(GSXML.DISPLAY_TEXT_ELEM + GSXML.LIST_MODIFIER)) {
+		tq_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_NAME, getTextString(TEXT_QUERY_SERVICE+".name", lang)));
+		tq_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_SUBMIT, getTextString(TEXT_QUERY_SERVICE+".submit", lang)));
+		tq_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_DESCRIPTION, getTextString(TEXT_QUERY_SERVICE+".description", lang)));
+	    } 
+	    if (subset == null || subset.equals(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER)) {
+		Element param_list = this.doc.createElement(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+		tq_service.appendChild(param_list);
+		Element param = GSXML.createParameterDescription(this.doc, QUERY_PARAM, getTextString("param."+QUERY_PARAM, lang), GSXML.PARAM_TYPE_STRING, null, null, null);
+		param_list.appendChild(param);
+		String [] field_ids = {"kw", "au", "su", "ti", "de", "fu"};
+		String [] field_names = {
+		    getTextString("param."+FIELD_PARAM+".kw", lang), 
+		    getTextString("param."+FIELD_PARAM+".au", lang), 
+		    getTextString("param."+FIELD_PARAM+".su", lang), 
+		    getTextString("param."+FIELD_PARAM+".ti", lang), 
+		    getTextString("param."+FIELD_PARAM+".de", lang), 
+		    getTextString("param."+FIELD_PARAM+".fu", lang) };
+		
+		param = GSXML.createParameterDescription(this.doc, FIELD_PARAM, getTextString("param."+FIELD_PARAM, lang), GSXML.PARAM_TYPE_ENUM_MULTI, "kw,au,su,ti,de,fu", field_ids, field_names);
+		param_list.appendChild(param);
+		
+		
+		String [] hits_options = {"10", "30", "50"};
+		param = GSXML.createParameterDescription(this.doc, GS_HITS_PARAM, getTextString("param."+GS_HITS_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, "10", hits_options, hits_options);
+		param_list.appendChild(param);
+		
+		param = GSXML.createParameterDescription(this.doc, GS_START_PAGE_PARAM, "", GSXML.PARAM_TYPE_INVISIBLE, "1", null, null);
+		param_list.appendChild(param);
+	    }
+	    return tq_service;
+	} 
+	if (service.equals(DOC_META_SERVICE)) {
+	    Element dm_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    dm_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
+	    dm_service.setAttribute(GSXML.NAME_ATT, DOC_META_SERVICE);
+	    return dm_service;
+
+	}
+	if (service.equals(DOC_CONTENT_SERVICE)) {
+	    Element dc_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    dc_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
+	    dc_service.setAttribute(GSXML.NAME_ATT, DOC_CONTENT_SERVICE);
+	    return dc_service;
+	    
+	    
+	}
+	return null;
+    }
+   
+    /** Process a text query - implemented by concrete subclasses */
+    protected Element processTextQuery(Element request) {
+
+	// Create a new (empty) result message
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.setAttribute(GSXML.FROM_ATT, TEXT_QUERY_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+	Element doc_node_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(doc_node_list);
+       
+
+	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (param_list == null) {
+	    logger.error("TextQuery request had no paramList.");
+	    return result;  // Return the empty result
+	}
+
+	// Process the request parameters
+	HashMap params = GSXML.extractParams(param_list, false);
+
+	// Make sure a query has been specified
+	String query = (String) params.get(QUERY_PARAM);
+	if (query == null || query.equals("")) {
+	    return result;  // Return the empty result
+	}
+	// tidy whitespace
+	query = query.replaceAll("\\s+", "+");
+	String url_string = ivia_server_url+"/cgi-bin/canned_search?theme=gsdl3&query="+query; 
+
+	// check for fields
+	String fields = (String) params.get(FIELD_PARAM);
+	if (fields != null && !fields.equals("")) {
+	    url_string += "&fields="+fields;
+	}
+
+	//check for hits per page
+	String hits_per_page = (String) params.get(GS_HITS_PARAM);
+	if (hits_per_page != null && !hits_per_page.equals("")) {
+	    url_string += "&"+IM_HITS_PARAM+"="+hits_per_page;
+	}
+
+	// check for start page
+	String start_page = (String) params.get(GS_START_PAGE_PARAM);
+	if (start_page != null && !start_page.equals("")) {
+	    url_string += "&"+IM_START_PAGE_PARAM+"="+start_page;
+	}
+	String results_num = null;
+	String doc_ids = null;
+	try {
+	    logger.debug("IViaProxy, sending "+url_string);
+	    BufferedReader reader = makeConnection(url_string);
+	    results_num = reader.readLine();
+	    doc_ids = reader.readLine();
+	    
+	} catch (Exception e) {
+	    logger.error("exception happened during query");
+	    e.printStackTrace();
+	    return result;
+	}
+	    
+	if (results_num.startsWith("Resources: ")) {
+	    results_num = results_num.substring(11);
+	} else {
+	    logger.error("badly formatted results line: "+results_num);
+	    return result;
+	}
+	if (doc_ids.startsWith("Ids: ")) {
+	    doc_ids = doc_ids.substring(5).trim();
+	} else {
+	    logger.error("badly formatted docs line: "+doc_ids);
+	    return result;
+	}
+	
+	// get the num docs and add to a metadata list
+	Element metadata_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER); 
+	result.appendChild(metadata_list);
+	
+	// Add a metadata element specifying the number of matching documents
+	long numdocs = Long.parseLong(results_num);
+	GSXML.addMetadata(this.doc, metadata_list, "numDocsMatched", ""+numdocs);	
+	String [] ids = doc_ids.split(" ");
+	
+	for (int d=0; d<ids.length; d++) {
+	    Element doc_node = this.doc.createElement(GSXML.DOC_NODE_ELEM);
+	    doc_node.setAttribute(GSXML.NODE_ID_ATT, ids[d]);
+	    doc_node_list.appendChild(doc_node);
+	}
+	logger.debug("IViaProxy result:");
+	logger.debug(this.converter.getString(result));
+	return result;
+	
+    }
+     
+    protected Element processDocumentMetadataRetrieve(Element request) {
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.setAttribute(GSXML.FROM_ATT, DOC_META_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+
+	// Get the parameters of the request
+	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (param_list == null) {
+	    logger.error("missing paramList.\n");
+	    return result;  // Return the empty result
+	}
+
+	// The metadata information required
+	StringBuffer field_list = new StringBuffer();
+	Element param = (Element) param_list.getFirstChild();
+	while (param != null) {
+	    // Identify the metadata information desired
+	    if (param.getAttribute(GSXML.NAME_ATT).equals("metadata")) {
+		String metadata = GSXML.getValue(param);
+		if (isAcceptableMetadata(metadata)) {
+		    field_list.append(metadata);
+		    field_list.append(",");	
+		}
+	    }
+	    param = (Element) param.getNextSibling();
+	}
+	
+	if (field_list.length()==0) {
+	    logger.error("no metadata specified.\n"); 
+	    return result;
+	}
+	    
+	// Get the documents
+	Element request_node_list = (Element) GSXML.getChildByTagName(request, GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	if (request_node_list == null) {
+	    logger.error("DocumentMetadataRetrieve request had no "+GSXML.DOC_NODE_ELEM+"List.\n");
+ 	    return result;
+ 	}
+	
+	StringBuffer record_id_list = new StringBuffer();
+	
+	NodeList request_nodes = request_node_list.getChildNodes();
+	for (int i = 0; i < request_nodes.getLength(); i++) {
+	    Element request_node = (Element) request_nodes.item(i);
+	    String node_id = request_node.getAttribute(GSXML.NODE_ID_ATT);
+	    record_id_list.append(node_id);
+	    record_id_list.append(",");
+	}
+
+	// do the query to the iVia server
+	String url_string = ivia_server_url+"/cgi-bin/view_record_set?theme=gsdl3&record_id_list="+record_id_list.toString()+"&field_list="+field_list.toString(); 
+
+	Element node_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(node_list);
+	try {
+	    BufferedReader reader = makeConnection(url_string);
+	    String line;
+	    while ((line = reader.readLine()) != null) {
+		if (!line.startsWith("Record:")) {
+		    continue;
+		}
+		// the first line is the record
+		line=line.substring(8);
+		Element doc_node = this.doc.createElement(GSXML.DOC_NODE_ELEM);
+		doc_node.setAttribute(GSXML.NODE_ID_ATT, line);
+		Element meta_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+		doc_node.appendChild(meta_list);
+		while  ((line = reader.readLine()) != null) {
+		    //metadata entry
+		    int col_pos = line.indexOf(':');
+		    if (col_pos == -1) {
+			// end of the metadata for this doc
+			break; 
+		    }
+		    String name = line.substring(0,col_pos);
+		    String value = line.substring(col_pos+2); // includes a space
+		    GSXML.addMetadata(this.doc, meta_list, name, value);
+		}
+		node_list.appendChild(doc_node);
+		
+	    }
+	} catch (Exception e) {
+	    logger.error("exception happened");
+	    e.printStackTrace();
+	}
+	logger.debug("IViaProxy: returning result: ");
+	logger.debug(this.converter.getPrettyString(result));
+	return result;
+ 
+    }
+
+    protected Element processDocumentContentRetrieve(Element request) {
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.setAttribute(GSXML.FROM_ATT, DOC_CONTENT_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+	
+	// Get the request doc_list
+	Element query_doc_list = (Element) GSXML.getChildByTagName(request, GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	if (query_doc_list == null) {
+	    logger.error("DocumentContentRetrieve request specified no doc nodes.\n");
+	    return result;
+	}
+
+	Element doc_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(doc_list);
+	
+	// Get the documents
+	String[] doc_ids = GSXML.getAttributeValuesFromList(query_doc_list, 
+						     GSXML.NODE_ID_ATT);
+	for (int i = 0; i < doc_ids.length; i++) {
+	    String doc_id = doc_ids[i];
+	    Element doc_node = getDocument(doc_id); 
+	    doc_list.appendChild(doc_node);
+	}
+	return result;
+
+    }
+
+
+    /** gets a document by sending a request to iVia, then processes it and creates a documentNode around the text */
+    protected Element getDocument(String doc_id) {
+
+	String url_string = ivia_server_url+"/cgi-bin/view_record?theme=gsdl3&record_id="+doc_id;
+	StringBuffer buffer = new StringBuffer();
+	try {
+	    BufferedReader reader = makeConnection(url_string);
+    
+	    String line;
+	    while((line = reader.readLine())!= null) {
+		buffer.append(line);
+	    }
+
+	    
+	} catch (Exception e) {
+	    logger.error("exception happened");
+	    e.printStackTrace();
+	}
+	
+	String node_content = buffer.toString(); 
+	String escaped_content = GSXML.xmlSafe(node_content);
+	
+	StringBuffer processed_content = new StringBuffer(escaped_content.length());
+	processed_content.append("<nodeContent>");
+	int pos = 0;
+	int lastpos = 0;
+	while ((pos = escaped_content.indexOf("&lt;a ", lastpos))!= -1) {
+	    processed_content.append(escaped_content.substring(lastpos, pos));
+	    int endpos = escaped_content.indexOf("&lt;/a&gt;", pos);
+	    if (endpos == -1) {
+		break;
+	    }
+	    String link = escaped_content.substring(pos, endpos+10);
+	    link = convertLink(link);
+	    processed_content.append(link);
+	    lastpos = endpos+10;
+	}
+	processed_content.append(escaped_content.substring(lastpos)); // get the last bit
+	processed_content.append("</nodeContent>");
+	    
+	Element doc_node = this.doc.createElement(GSXML.DOC_NODE_ELEM);
+	doc_node.setAttribute(GSXML.NODE_ID_ATT, doc_id);
+	
+	Document content_doc = this.converter.getDOM(processed_content.toString());
+	if (content_doc != null) {
+	    Element content_element = content_doc.getDocumentElement();
+	    doc_node.appendChild(this.doc.importNode(content_element, true));
+	} else {
+	    logger.error("Couldn't parse the node content");
+	}
+	return doc_node;
+	
+    }
+
+    /** converts a url from an <a> element into a greenstone suitable one */
+    protected String convertLink(String aref) {
+	
+	if (aref.indexOf("href=&quot;http") != -1) {
+	    return aref; // an external link
+	}
+	String type = "other";
+	if (aref.indexOf("/cgi-bin/canned_search")!=-1) {
+	    type="query";
+	} else if (aref.indexOf("/cgi-bin/click_through") != -1) {
+	    type = "external";
+	} else if (aref.indexOf("/cgi-bin/view_record") != -1) {
+	    type="document";
+	} 
+	
+	int href_start = aref.indexOf("href=&quot;")+11;
+	int href_end = aref.indexOf("&gt;", href_start);
+	String href = aref.substring(href_start, href_end);
+	String link_content = aref.substring(href_end+4, aref.length()-10);
+	
+	if (type.equals("external")) {
+	    // the external link is everything after the http at the end.
+	    String address = href.substring(href.lastIndexOf("http"));
+	    address = address.replaceAll("%3[aA]", ":");
+	    address = address.replaceAll("%2[fF]", "/");
+
+	    return "&lt;a href=\""+address+"\"&gt;"+link_content+"&lt;/a&gt;";
+	}
+	if (type.equals("other")) {
+	    return "other type of link ("+link_content+")";
+	}
+	StringBuffer result = new StringBuffer();
+	result.append("<link type='");
+	result.append(type);
+	result.append("'");
+	if (type.equals("query")) {
+	    result.append(" service='TextQuery'");
+	}
+	result.append(">");
+	// add in the parameters
+	href = href.substring(href.indexOf("?")+1);
+	String [] params = href.split("&amp;");
+	for (int i=0; i<params.length; i++) {
+	    String param = params[i];
+	    int eq_pos = param.indexOf("=");
+	    if (eq_pos != -1) {
+		
+		result.append("<param name='"+param.substring(0, eq_pos)+"' value='"+param.substring(eq_pos+1)+"'/>");
+	    }
+	}
+	result.append(link_content);
+	result.append("</link>");
+
+	return result.toString();
+	    
+    }
+
+    // iVia craps out if we ask for a metadata which is not valid. So need
+    // to make sure we only ask for acceptable fields.
+    protected boolean isAcceptableMetadata(String meta) {
+	String valid_metadata = ",title,url,ivia_description,keywords,subjects,";
+	if (valid_metadata.indexOf(","+meta+",")!=-1) {
+	    return true;
+	}
+	return false;
+    }
+    protected BufferedReader makeConnection(String url_string) {
+	BufferedReader reader = null;
+	try {
+	    URL url = new URL(url_string);
+	    HttpURLConnection connection = (HttpURLConnection)url.openConnection();
+	    InputStream input = connection.getInputStream();
+	    reader = new BufferedReader(new InputStreamReader(input));  
+	} catch (java.net.MalformedURLException e) {
+
+	    logger.error("Malformed URL: "+url_string);
+	} catch (java.io.IOException e) {
+	    logger.error("An error occurred during IO to url "+url_string);
+	}
+	return reader;
+    }
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/IViaRetrieve.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/IViaRetrieve.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/IViaRetrieve.java	(revision 14125)
@@ -0,0 +1,262 @@
+package org.greenstone.gsdl3.service;
+
+// Greenstone classes
+import org.greenstone.gsdl3.core.GSException;
+import org.greenstone.gsdl3.util.*;
+
+// XML classes
+import org.w3c.dom.Element; 
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList; 
+
+import java.util.HashMap;
+import java.util.ArrayList;
+import java.io.File;
+import java.io.InputStream;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URLConnection;
+import java.net.URL;
+import java.net.Authenticator;
+import java.net.MalformedURLException;
+
+import org.apache.log4j.*;
+
+/**
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @version $Revision$
+ * Modified by  <a href="mailto:chi@cs.waikato.ac.nz">Chi-Yu Huang</a>
+ */
+
+public class IViaRetrieve 
+    extends AbstractDocumentRetrieve {
+
+      static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.IViaRetrieve.class.getName());
+    
+
+    protected String ivia_server_url = null;
+    
+    public IViaRetrieve() {
+	does_structure = false;
+    }
+    
+    //Configure IViaRetrieve Service
+    public boolean configure(Element info, Element extra_info) 
+    {
+	if (!super.configure(info, extra_info)) {
+	    return false;
+	}
+	
+	Element server_elem = (Element)GSXML.getChildByTagName(info, "iViaServer");
+	if (server_elem == null) {
+	    logger.error("no iViaServer element found");
+	    return false;
+	}
+	ivia_server_url = server_elem.getAttribute("url");
+	if (ivia_server_url.equals("")) {
+	    logger.error("no url for the iViaServer element");
+	    return false;
+	}
+	return true;
+	
+    }
+        
+    /** gets a document by sending a request to iVia, then processes it and creates a documentNode around the text */
+    protected Element getNodeContent(String doc_id, String lang) 
+	throws GSException {
+
+	String url_string = ivia_server_url+"/cgi-bin/view_record?theme=gsdl3&record_id="+doc_id;
+
+	StringBuffer buffer = new StringBuffer();
+	try {
+	    BufferedReader reader = Misc.makeHttpConnection(url_string);
+    	    String line;
+	    while((line = reader.readLine())!= null) {
+		buffer.append(line);
+	    }
+   	} catch (java.net.MalformedURLException e) {
+	    throw new GSException("Malformed URL: "+url_string, GSXML.ERROR_TYPE_SYSTEM);
+	} catch (java.io.IOException e) {
+	    throw new GSException("IOException during connection to "+url_string+": "+e.toString(),GSXML.ERROR_TYPE_SYSTEM);
+	}
+
+	String node_content = buffer.toString(); 
+
+	String escaped_content = GSXML.xmlSafe(node_content);
+	
+	StringBuffer processed_content = new StringBuffer(escaped_content.length());
+	processed_content.append("<nodeContent>");
+	int pos = 0;
+	int lastpos = 0;
+	while ((pos = escaped_content.indexOf("&lt;a ", lastpos))!= -1) {
+	    processed_content.append(escaped_content.substring(lastpos, pos));
+	    int endpos = escaped_content.indexOf("&lt;/a&gt;", pos);
+	    if (endpos == -1) {
+		break;
+	    }
+	    String link = escaped_content.substring(pos, endpos+10);
+	    link = convertLink(link);
+	    processed_content.append(link);
+	    lastpos = endpos+10;
+	}
+	processed_content.append(escaped_content.substring(lastpos)); // get the last bit
+	processed_content.append("</nodeContent>");
+	    
+	Document content_doc = this.converter.getDOM(processed_content.toString());
+	if (content_doc == null) {
+	    logger.error("Couldn't parse node content");
+	    logger.error(processed_content.toString());
+	    return null;
+	}
+	
+	Element content_element = content_doc.getDocumentElement();
+
+	return (Element)this.doc.importNode(content_element,true);
+    }
+	
+    /** converts a url from an <a> element into a greenstone suitable one */
+    protected String convertLink(String aref) {
+	if (aref.indexOf("href=&quot;http") != -1) {
+	    return aref; // an external link
+	}
+	String type = "other";
+	if (aref.indexOf("/cgi-bin/canned_search")!=-1) {
+	    type="query";
+	} else if (aref.indexOf("/cgi-bin/click_through") != -1) {
+	    type = "external";
+	} else if (aref.indexOf("/cgi-bin/view_record") != -1) {
+	    type="document";
+	} 
+	
+	int href_start = aref.indexOf("href=&quot;")+11;
+	int href_end = aref.indexOf("&gt;", href_start);
+	String href = aref.substring(href_start, href_end);
+	String link_content = aref.substring(href_end+4, aref.length()-10);
+	
+	if (type.equals("external")) {
+	    // the external link is everything after the http at the end.
+	    String address = href.substring(href.lastIndexOf("http"));
+	    address = address.replaceAll("%3[aA]", ":");
+	    address = address.replaceAll("%2[fF]", "/");
+
+	    return "&lt;a href=\""+address+"\"&gt;"+link_content+"&lt;/a&gt;";
+	}
+	if (type.equals("other")) {
+	    return "other type of link ("+link_content+")";
+	}
+	StringBuffer result = new StringBuffer();
+	result.append("<link type='");
+	result.append(type);
+	result.append("'");
+	if (type.equals("query")) {
+	    result.append(" service='TextQuery'");
+	}
+	result.append(">");
+	// add in the parameters
+	href = href.substring(href.indexOf("?")+1);
+	String [] params = href.split("&amp;");
+	for (int i=0; i<params.length; i++) {
+	    String param = params[i];
+	    int eq_pos = param.indexOf("=");
+	    if (eq_pos != -1) {
+		
+		result.append("<param name='"+param.substring(0, eq_pos)+"' value='"+param.substring(eq_pos+1)+"'/>");
+	    }
+	}
+	result.append(link_content);
+	result.append("</link>");
+
+	return result.toString();
+    }
+
+    // iVia craps out if we ask for a metadata which is not valid. So need
+    // to make sure we only ask for acceptable fields.
+    protected boolean isAcceptableMetadata(String meta) {
+	String valid_metadata = ",title,url,ivia_description,keywords,subjects,";
+	if (valid_metadata.indexOf(","+meta+",")!=-1) {
+	    return true;
+	}
+	return false;
+    }
+
+    protected String translateId(String oid){
+	int p = oid.lastIndexOf('.');
+	if (p != oid.length()-3) {
+	    logger.info("translateoid error: '.' is not the third to last char!!");
+	    return oid;
+	}
+	String top = oid.substring(0, p);
+	return top;
+    }
+
+    protected String translateExternalId(String id){
+	return id;
+    }
+
+    protected String getDocType(String node_id){
+    	return GSXML.DOC_TYPE_SIMPLE;
+    }
+    protected String getRootId(String node_id){
+   	return node_id; 
+    }
+
+    protected ArrayList getChildrenIds(String node_id){
+	return null; 
+    }
+    
+    protected String getParentId(String node_id){
+	return null;
+    }
+    
+    protected Element getMetadataList (String doc_id,
+				       boolean all_metadata,
+				       ArrayList metadata_names) 
+	throws GSException {
+	
+	Element meta_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+
+	// do the query to the iVia server
+	StringBuffer field_list= new StringBuffer();
+	boolean metadata_found = false;
+
+	for (int i=0; i<metadata_names.size();i++){
+	    if (isAcceptableMetadata((String)metadata_names.get(i))){
+		metadata_found = true;
+		field_list.append((String)metadata_names.get(i));
+		field_list.append(",");
+	    }
+	}
+	if (!metadata_found){
+	    return meta_list;
+	}
+	
+	String url_string = ivia_server_url+"/cgi-bin/view_record_set?theme=gsdl3&record_id_list="+doc_id+"&field_list="+field_list.toString(); 
+	try {
+	    BufferedReader reader = Misc.makeHttpConnection(url_string);
+	    String line;
+	    while  ((line = reader.readLine()) != null) {
+		//metadata entry
+		int col_pos = line.indexOf(':');
+		if (col_pos == -1) {
+		    // end of the metadata for this doc
+		    break; 
+		}
+		String name = line.substring(0,col_pos);
+		String value = line.substring(col_pos+2); // includes a space
+		GSXML.addMetadata(this.doc, meta_list, name, value);
+	    }
+	} catch (java.net.MalformedURLException e) {
+	    throw new GSException("Malformed URL: "+url_string, GSXML.ERROR_TYPE_SYSTEM);
+	} catch (java.io.IOException e) {
+	    throw new GSException("IOException: "+e.toString(), GSXML.ERROR_TYPE_SYSTEM);
+	}
+	return meta_list;
+    }
+    
+    protected String getStructureInfo(String doc_id, String info_type){
+	return "";	
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/IViaSearch.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/IViaSearch.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/IViaSearch.java	(revision 14125)
@@ -0,0 +1,206 @@
+package org.greenstone.gsdl3.service;
+
+// Greenstone classes
+import org.greenstone.gsdl3.util.*;
+
+// XML classes
+import org.w3c.dom.Element; 
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList; 
+
+//Java classes
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.io.File;
+import java.io.BufferedReader;
+import java.net.Authenticator;
+
+import org.apache.log4j.*;
+
+/**
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @author <a href="mailto:chi@cs.waikato.ac.nz">Chi-Yu Huang</a>
+ */
+
+public class IViaSearch
+    extends AbstractSearch {
+    
+
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.IViaSearch.class.getName());
+ 
+    // have standard gs param names for hits per page, and start page
+    // these need to be mapped to iVia params
+    protected static final String IM_HITS_PARAM = "no_of_records_per_page";
+    protected static final String IM_START_PAGE_PARAM = "start_page_no";
+
+    protected String ivia_server_url = null;
+    protected ArrayList index_ids = null;
+    public IViaSearch()
+    {
+    }
+    
+    //Configure IViaSearch Service
+    public boolean configure(Element info, Element extra_info) 
+    { 
+	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+
+	Element server_elem = (Element)GSXML.getChildByTagName(info, "iViaServer");
+	if (server_elem == null) {
+	    logger.error("no iViaServer element found");
+	    return false;
+	}
+	ivia_server_url = server_elem.getAttribute("url");
+	if (ivia_server_url.equals("")) {
+	    logger.error("no url for the iViaServer element");
+	    return false;
+	}
+	does_paging = true;
+	does_multi_index_search = true;
+	this.default_index = ",kw,au,su,ti,de,fu,"; // all of them
+	index_ids = new ArrayList();
+	index_ids.add("kw");
+	index_ids.add("au");	
+	index_ids.add("su");	
+	index_ids.add("ti");
+	index_ids.add("de");
+	index_ids.add("fu");
+
+	return true;
+    }
+    
+    /** Process a text query - implemented by concrete subclasses */
+    protected Element processTextQuery(Element request) {
+	// Create a new (empty) result message
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.setAttribute(GSXML.FROM_ATT, TEXT_QUERY_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+	Element doc_node_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(doc_node_list);
+	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (param_list == null) {
+	    logger.error("TextQuery request had no paramList.");
+	    return result;  // Return the empty result
+	}
+
+	// Process the request parameters
+	HashMap params = GSXML.extractParams(param_list, false);
+
+	// Make sure a query has been specified
+	String query = (String) params.get(QUERY_PARAM);
+	if (query == null || query.equals("")) {
+	    return result;  // Return the empty result
+	}
+
+	// tidy whitespace
+	query = query.replaceAll("\\s+", "+");
+	String url_string = ivia_server_url+"/cgi-bin/canned_search?theme=gsdl3&query="+query; 
+
+	// check for fields
+	String fields = (String) params.get(INDEX_PARAM);
+	fields = checkFieldParam(fields); // removes invalid fields
+	if (!fields.equals("")) {
+	    url_string += "&fields="+fields;
+	}
+	//check for hits per page
+	String hits_per_page = (String) params.get(HITS_PER_PAGE_PARAM);
+	if (hits_per_page != null && !hits_per_page.equals("")) {
+	    url_string += "&"+IM_HITS_PARAM+"="+hits_per_page;
+	}
+
+	// check for start page
+	String start_page = (String) params.get(START_PAGE_PARAM);
+	if (start_page != null && !start_page.equals("")) {
+	    url_string += "&"+IM_START_PAGE_PARAM+"="+start_page;
+	}
+	String results_num = null;
+	String doc_ids = null;
+	BufferedReader reader = null;
+	try {
+	    logger.debug("sending "+url_string);
+	    reader = Misc.makeHttpConnection(url_string);
+	    results_num = reader.readLine();
+	    doc_ids = reader.readLine();
+	} catch (java.net.MalformedURLException e) {
+	    GSXML.addError(this.doc, result, "Malformed URL: "+url_string);
+	    return result;
+	} catch (java.io.IOException e) {
+	    GSXML.addError(this.doc, result, "IOException during connection to "+url_string+": "+e.toString());
+	    return result;
+	}
+	    
+	if (results_num.startsWith("Resources: ") && doc_ids.startsWith("Ids: ")) {
+	    results_num = results_num.substring(11);
+	    doc_ids = doc_ids.substring(5).trim();
+
+	} else {
+	    logger.error("badly formatted results:");
+	    StringBuffer result_string = new StringBuffer();
+	    result_string.append("Error: badly formatted result from IVia server:\n ");
+	    result_string.append(results_num);
+	    result_string.append(doc_ids);
+	    String line;
+	    try {
+		while((line = reader.readLine()) != null) {
+		    result_string.append(line);
+		}
+	    } catch (Exception e) {
+		result_string.append("Exception: "+e);
+	    }
+	    GSXML.addError(this.doc, result, result_string.toString());
+	    
+	    return result;
+	}
+	
+	// get the num docs and add to a metadata list
+	Element metadata_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER); 
+	result.appendChild(metadata_list);
+	
+	// Add a metadata element specifying the number of matching documents
+	long numdocs = Long.parseLong(results_num);
+	GSXML.addMetadata(this.doc, metadata_list, "numDocsMatched", ""+numdocs);	
+	String [] ids = doc_ids.split(" ");
+	
+	for (int d=0; d<ids.length; d++) {
+	    Element doc_node = this.doc.createElement(GSXML.DOC_NODE_ELEM);
+	    doc_node.setAttribute(GSXML.NODE_ID_ATT, ids[d]);
+	    doc_node_list.appendChild(doc_node);
+	}
+	return result;
+    }
+     
+    protected String checkFieldParam(String fields) {
+	
+	if (fields == null) {
+	    // return the default
+	    return "";
+	}
+	StringBuffer new_fields = new StringBuffer();
+	String [] ids = fields.split(",");
+	for (int i=0; i<ids.length; i++) {
+	    if(index_ids.contains(ids[i])) {
+		new_fields.append(ids[i]);
+		new_fields.append(",");
+	    }
+	}
+	if (new_fields.length() == 0) {
+	    return "";
+	}
+	return new_fields.toString();
+    }
+    /**
+       An IVia server has a fixed list of fields to search (I think) so we can hard code them here rather than reading them in from a config file
+    */
+    protected void getIndexData(ArrayList index_ids, ArrayList index_names,String lang){
+	index_ids.addAll(this.index_ids);
+	index_names.add(getTextString("param."+INDEX_PARAM+".kw", lang)); 
+	index_names.add(getTextString("param."+INDEX_PARAM+".au", lang));
+	index_names.add(getTextString("param."+INDEX_PARAM+".su", lang));
+	index_names.add(getTextString("param."+INDEX_PARAM+".ti", lang));
+	index_names.add(getTextString("param."+INDEX_PARAM+".de", lang));
+	index_names.add(getTextString("param."+INDEX_PARAM+".fu", lang));
+    }
+    
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/LuceneSearch.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/LuceneSearch.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/LuceneSearch.java	(revision 14125)
@@ -0,0 +1,137 @@
+package org.greenstone.gsdl3.service;
+
+// Greenstone classes
+import org.greenstone.gsdl3.util.*;
+
+// XML classes
+import org.w3c.dom.Element; 
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList; 
+
+import java.util.HashMap;
+import java.util.ArrayList;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.document.*; //Document;
+import org.apache.lucene.search.Searcher;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Hits;
+import org.apache.lucene.queryParser.QueryParser;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.index.Term;
+
+import java.io.File;
+
+import org.apache.log4j.*;
+
+/**
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @version $Revision$
+ */
+
+public class LuceneSearch 
+    extends AbstractSearch {
+
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.LuceneSearch.class.getName());
+
+    protected static final String INDEX_ELEM = "index";
+    
+    public boolean configure(Element info, Element extra_info) {
+	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+	
+	default_index = "idx";
+	return true;
+    }
+    
+    protected void getIndexData(ArrayList index_ids, ArrayList index_names, String lang) 
+    {
+	// the index info - read from config file - cache it??
+	Element index_list = (Element)GSXML.getChildByTagName(this.config_info, INDEX_ELEM+GSXML.LIST_MODIFIER);
+	if (index_list != null) {
+	    NodeList indexes = index_list.getElementsByTagName(INDEX_ELEM);
+	    int len = indexes.getLength();
+	    // now add even if there is only one
+	    for (int i=0; i<len; i++) {
+		Element index = (Element)indexes.item(i);
+		index_ids.add(index.getAttribute(GSXML.NAME_ATT));
+		index_names.add(GSXML.getDisplayText(index, GSXML.DISPLAY_TEXT_NAME, lang, "en"));
+		
+	    }
+	} else {
+	    // there is only one index, so we assume the default
+	    index_ids.add(this.default_index);
+	    index_names.add("Default index");
+	}
+
+    }
+
+    /** Process a text query - implemented by concrete subclasses */
+    protected Element processTextQuery(Element request) {
+
+	// Create a new (empty) result message
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.setAttribute(GSXML.FROM_ATT, TEXT_QUERY_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+	Element doc_node_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(doc_node_list);
+	Element metadata_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(metadata_list);
+	// Get the parameters of the request
+	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (param_list == null) {
+	    logger.error("TextQuery request had no paramList.");
+	    GSXML.addMetadata(this.doc, metadata_list, "numDocsMatched", "0");
+	    return result;  // Return the empty result
+	}
+
+	// Process the request parameters
+	HashMap params = GSXML.extractParams(param_list, false);
+
+	// Make sure a query has been specified
+	String query_string = (String) params.get(QUERY_PARAM);
+	if (query_string == null || query_string.equals("")) {
+	    logger.error("TextQuery request had no query string.");
+	    GSXML.addMetadata(this.doc, metadata_list, "numDocsMatched", "0");
+	    return result;  // Return the empty result
+	}
+
+	// Get the index
+	String index = (String) params.get(INDEX_PARAM);
+	if (index == null || index.equals("")) {
+	    index = this.default_index; // assume the default
+	}
+        try {
+	    String index_dir = GSFile.collectionIndexDir(this.site_home, this.cluster_name);
+	    index_dir += File.separator+index;
+	    Searcher searcher = new IndexSearcher(index_dir);
+	    Analyzer analyzer = new StandardAnalyzer();
+	    
+	    Term term = new Term("content", query_string);
+        
+	    Query query = new TermQuery(term);
+
+	    Hits hits = searcher.search(query);
+	    GSXML.addMetadata(this.doc, metadata_list, "numDocsMatched", ""+hits.length());
+	    
+	    for (int i=0; i<hits.length(); i++) {
+		org.apache.lucene.document.Document luc_doc = hits.doc(i);
+		String node_id = luc_doc.get("nodeID");
+		Element node = this.doc.createElement(GSXML.DOC_NODE_ELEM);
+		node.setAttribute(GSXML.NODE_ID_ATT, node_id);
+		doc_node_list.appendChild(node);
+	    }
+	} catch (Exception e) {
+	    e.printStackTrace();
+	}
+	
+	return result;
+	    
+    }
+
+    
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/MapRetrieve.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/MapRetrieve.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/MapRetrieve.java	(revision 14125)
@@ -0,0 +1,840 @@
+package org.greenstone.gsdl3.service;
+
+// Greenstone classes
+import org.greenstone.gsdl3.util.*;
+
+// XML classes
+import org.w3c.dom.Document;
+import org.w3c.dom.Element; 
+import org.w3c.dom.NodeList;
+
+// General Java classes
+import java.io.File;
+import java.io.*;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import java.util.Set;
+import java.util.Iterator;
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import javax.swing.tree.DefaultMutableTreeNode;
+
+import org.apache.log4j.*;
+
+public class MapRetrieve
+    extends ServiceRack {
+
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.MapRetrieve.class.getName());
+
+    // the services on offer
+    protected static final String DOCUMENT_STRUCTURE_RETRIEVE_SERVICE = "DocumentStructureRetrieve";
+    protected static final String DOCUMENT_METADATA_RETRIEVE_SERVICE = "DocumentMetadataRetrieve";
+    protected static final String DOCUMENT_CONTENT_RETRIEVE_SERVICE = "DocumentContentRetrieve";
+
+    protected static final int DOCUMENT=1;
+
+    protected ArrayList index_name_list = null;
+    protected ArrayList index_display_list = null;
+    protected String files_home_dir = null; 
+    protected String temp_files_dir = null;
+    //protected String temp_image_file = null;
+    //protected String temp_image_file2 = null;
+    protected final String jpg_ext = ".jpg";
+    protected String http_image_dir = null;
+    protected String http_temp_image_dir = null;
+    private LinkedList namesInList = new LinkedList();
+
+    private DefaultMutableTreeNode tree;
+
+    /** constructor */
+    public MapRetrieve() {}
+
+
+    /** configure this service */
+    public boolean configure(Element info, Element extra_info)
+    {
+	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+
+	logger.info("Configuring MapRetrieve...");
+	this.config_info = info;
+
+	// set up short_service_info_ - for now just has name and type
+	Element dmr_service = doc.createElement(GSXML.SERVICE_ELEM);
+	dmr_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
+	dmr_service.setAttribute(GSXML.NAME_ATT, DOCUMENT_METADATA_RETRIEVE_SERVICE);
+	short_service_info.appendChild(dmr_service);
+
+	Element dcr_service = doc.createElement(GSXML.SERVICE_ELEM);
+	dcr_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
+	dcr_service.setAttribute(GSXML.NAME_ATT, DOCUMENT_CONTENT_RETRIEVE_SERVICE);
+	short_service_info.appendChild(dcr_service);
+
+	Element dsr_service = doc.createElement(GSXML.SERVICE_ELEM);
+	dsr_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
+	dsr_service.setAttribute(GSXML.NAME_ATT, DOCUMENT_STRUCTURE_RETRIEVE_SERVICE);
+	short_service_info.appendChild(dsr_service);
+
+	// set the files_home variable for this collection
+	this.files_home_dir = GSFile.collectionIndexDir(this.site_home, this.cluster_name)+ File.separator+"assoc"+File.separator; 
+	this.temp_files_dir = GSFile.collectionBaseDir(this.site_home, this.cluster_name) + File.separator + "temp"+File.separator; 
+
+	    //this.files_home_dir + "maps" + File.separator + "temp" + File.separator;
+	//this.temp_image_file = this.temp_files_dir+"temp_";
+	//this.temp_image_file2 = this.temp_files_dir+"temp2_";
+	
+	
+	this.http_image_dir = this.site_http_address + "/collect/"+this.cluster_name+"/index/assoc/maps/";
+	this.http_temp_image_dir = this.site_http_address + "/collect/"+this.cluster_name+"/temp/";
+
+	this.index_name_list = new ArrayList();
+	this.index_display_list = new ArrayList();
+	Element index_list = (Element)GSXML.getChildByTagName(this.config_info, GSXML.INDEX_ELEM+GSXML.LIST_MODIFIER);
+	Element display_index_list = (Element)GSXML.getChildByTagName(extra_info, "search");
+	if (index_list != null && display_index_list != null) {
+	    NodeList indexes = index_list.getElementsByTagName(GSXML.INDEX_ELEM);
+	    for (int i=0; i<indexes.getLength(); i++) {
+		String name = ((Element)indexes.item(i)).getAttribute(GSXML.NAME_ATT);
+		// add the index name
+		this.index_name_list.add(name);
+		// now look for the display name
+		Element this_index = GSXML.getNamedElement(display_index_list, "index", "name", name);
+		if (this_index != null) {
+		    Element disp = GSXML.getNamedElement(this_index, "displayItem", "name", "name");
+		    if (disp != null) {
+			String display = GSXML.getNodeText(disp);
+			if (!display.equals("")) {
+			    this.index_display_list.add(display);
+			    continue;
+			}
+			
+		    }
+		}
+		// add the id as default text
+		this.index_display_list.add(name);
+
+	    }
+	}
+
+	// look for document display format
+	String path = GSPath.appendLink(GSXML.DISPLAY_ELEM, GSXML.FORMAT_ELEM);
+	Element display_format = (Element)GSXML.getNodeByPath(extra_info, path);
+	if (display_format != null) {
+	    this.format_info_map.put(DOCUMENT_CONTENT_RETRIEVE_SERVICE, this.doc.importNode(display_format, true));
+	    // shoudl we make a copy?
+	}
+
+	// load the 2-dimensional tree for searching
+	try{
+	    ObjectInputStream objectin = new ObjectInputStream(new FileInputStream(this.files_home_dir+"nametree.dat"));
+	    tree = (DefaultMutableTreeNode)objectin.readObject();
+	    objectin.close();
+	}catch(IOException ioe){
+	    ioe.printStackTrace();
+	}catch(ClassNotFoundException cnfe){
+	    cnfe.printStackTrace();
+	}
+    
+
+	return true;
+    }
+
+    /** */
+    protected Element getServiceDescription(String service, String lang, String subset) 
+    {
+	if (service.equals(DOCUMENT_STRUCTURE_RETRIEVE_SERVICE)) {
+	    
+	    Element tq_service = doc.createElement(GSXML.SERVICE_ELEM);
+	    tq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
+	    tq_service.setAttribute(GSXML.NAME_ATT, DOCUMENT_STRUCTURE_RETRIEVE_SERVICE);
+	    return tq_service;
+	}
+	else if (service.equals(DOCUMENT_METADATA_RETRIEVE_SERVICE)) {
+	    
+	    Element tq_service = doc.createElement(GSXML.SERVICE_ELEM);
+	    tq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
+	    tq_service.setAttribute(GSXML.NAME_ATT, DOCUMENT_METADATA_RETRIEVE_SERVICE);
+	    return tq_service;
+	}
+	else if (service.equals(DOCUMENT_CONTENT_RETRIEVE_SERVICE)) {
+	    
+	    Element tq_service = doc.createElement(GSXML.SERVICE_ELEM);
+	    tq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
+	    tq_service.setAttribute(GSXML.NAME_ATT, DOCUMENT_CONTENT_RETRIEVE_SERVICE);
+	    return tq_service;
+	}
+
+	return null;
+	
+    }
+
+    /** Retrieve the structure of a document */
+    protected Element processDocumentStructureRetrieve(Element request)
+    {
+	// Create a new (empty) result message
+	Element result = doc.createElement(GSXML.RESPONSE_ELEM);
+	return result;
+    }
+
+    protected Element processDocumentMetadataRetrieve(Element request) {
+	// Create a new (empty) result message
+	try{
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+
+	String uid = request.getAttribute(GSXML.USER_ID_ATT);
+	if (uid.equals("")) {
+	    logger.info("in metadata retrieve, uid = ''\n"+converter.getPrettyString(request));
+	}
+	result.setAttribute(GSXML.FROM_ATT, DOCUMENT_METADATA_RETRIEVE_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+
+	// Get the parameters of the request
+	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (param_list == null) {
+	    logger.error("missing paramList.\n");
+	    return result;  // Return the empty result
+	}
+
+	// The metadata information required
+	Vector metadata_list = new Vector();
+	boolean all_metadata = false;
+	// Process the request parameters
+	Element param = (Element) param_list.getFirstChild();
+
+	while (param != null) {
+	    // Identify the metadata information desired
+	    if (param.getAttribute(GSXML.NAME_ATT).equals("metadata")) {
+		String metadata = GSXML.getValue(param);
+		if (metadata.equals("all")) {
+		    all_metadata = true;
+		    break;
+		}
+		metadata_list.add(metadata);
+	    }
+	    param = (Element) param.getNextSibling();
+	}
+
+	Element node_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(node_list);
+	
+	// Get the documents
+	Element request_node_list = (Element) GSXML.getChildByTagName(request, GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	if (request_node_list == null) {
+	    logger.error(" DocumentMetadataRetrieve request had no "+GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+ 	    return result;
+ 	}
+
+	NodeList request_nodes = request_node_list.getChildNodes();
+
+	try{
+	    //used just to ensure outfile is initialised
+	    BufferedWriter outfile = new BufferedWriter(new FileWriter(this.temp_files_dir+"emptynothingness"));
+	    
+	    for (int i = 0; i < request_nodes.getLength(); i++) {
+		Element request_node = (Element) request_nodes.item(i);
+		String node_id = request_node.getAttribute(GSXML.NODE_ID_ATT);
+		String place_data = "";
+		String year = "";
+		String coOrdinates = "";
+		String thumb = "";
+		String link = "";
+		int mapFreq = 0;
+		LinkedList place_data_list = new LinkedList();
+		LinkedList coOrdinates_list = new LinkedList();
+
+		//if this is a first displaying of the map
+		if(node_id.indexOf("```") != -1 && node_id.indexOf("imageChooser") == -1){
+		    //get the number of query terms on this map
+		    mapFreq = Integer.parseInt(node_id.substring(node_id.lastIndexOf('`',node_id.indexOf("```")-1)+1,node_id.indexOf("```")));
+		    //get the place names on this map
+		    place_data = node_id.substring(node_id.indexOf("```")+3,node_id.length());
+		    //get the map metadata
+		    node_id = node_id.substring(0,node_id.indexOf('`',node_id.indexOf("```")));
+		    
+		    try{
+			// loop for each query term on the map
+			for(int r=0; r<mapFreq; r++){
+			    // get title, type, location, and the string for creating the hyperlink for this query term
+			    String title = place_data.substring(0,place_data.indexOf('`'));
+			    String type = place_data.substring(place_data.indexOf('`')+1,place_data.indexOf('`',place_data.indexOf('`')+1));
+			    String location = place_data.substring(place_data.indexOf('`',place_data.indexOf('`')+1)+1, place_data.indexOf('`',place_data.indexOf('`',place_data.indexOf('`')+1)+1));
+			    if(place_data.indexOf("```") != -1)
+				link=place_data.substring(0,place_data.indexOf("```"));
+			    else
+				link=place_data;
+			    // resolve the type and location
+			    type = getType(type);
+			    location = getLocation(location);
+			    // remove this query term from the string
+			    if(place_data.indexOf("```") != -1)
+				place_data = place_data.substring(place_data.indexOf("```")+3,place_data.length());
+			    
+			    //add the co-ordinates of this query term to the co-ordinates list
+			    coOrdinates_list.add("`"+link.substring(link.lastIndexOf('`')+1,link.length())+"`"+link.substring(link.lastIndexOf('`',link.lastIndexOf('`')-1)+2,link.lastIndexOf('`')));
+			    
+			    // add the title, type and location to the places list
+			    place_data_list.add(title + ", " + type + ", " + location + ";");
+			}
+		    }catch(StringIndexOutOfBoundsException sioobe){sioobe.printStackTrace();}
+		}
+		
+		// Add the document to the list
+		Element new_node = (Element)this.doc.importNode(request_node, false);
+		node_list.appendChild(new_node);
+		
+		// Add the requested metadata information
+		Element node_meta_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+		new_node.appendChild(node_meta_list);
+		
+		// create the navigation thumbnails.  This doesn't seem to work most of the time ???????
+		for (int m = 0; m < metadata_list.size(); m++) {
+		    String metadata = (String) metadata_list.get(m);
+		    thumb = "";
+		    String value = "";
+		    if(node_id.indexOf('.') != -1) 
+			thumb = node_id.substring(0,node_id.indexOf('.'));
+		    if(node_id.indexOf('`') != -1) 
+			value = node_id.substring(node_id.lastIndexOf('`',node_id.lastIndexOf('`')-1)+1,node_id.lastIndexOf('`',node_id.lastIndexOf('`')-1)+5);
+		    year = value;
+		    
+		    place_data="";
+		    if(place_data_list.size() != 0)
+			for(int q=0; q<mapFreq; q++){
+			    link = (String)place_data_list.get(q);
+			    if(q!=0){
+				place_data = place_data + "<br>" + link;
+			    }
+			    else{
+				place_data = link;
+				coOrdinates = "``";
+			    }
+			    coOrdinates = coOrdinates+(String)coOrdinates_list.get(q);
+			}
+		    
+		    link = "<a href=\"?a=d&c="+this.cluster_name+"&d="+node_id+coOrdinates+"&dt=map\">";
+		    thumb = "<img src=\""+this.http_image_dir + thumb + "thumb.jpg\" border=0>";
+		    value = "<table><tr><td>"+link+"<p>"+place_data+"<br>"+value+"</a></td><td>"+link+thumb+"</a></td></tr></table>";
+		    if(metadata.equals("Title"))
+			if(!(place_data.equals("")) && place_data.indexOf(", , ;")==-1 && node_id.indexOf("```")==-1)
+			    GSXML.addMetadata(this.doc, node_meta_list, "Title", value);//metadata, value);
+			else
+			    GSXML.addMetadata(this.doc, node_meta_list, metadata, "");
+		    
+		    if(place_data.indexOf(", , ;")==-1){
+			if(i==0)
+			    if(!(mapFreq==0)){
+				outfile = new BufferedWriter(new FileWriter(this.temp_files_dir+"links"+uid));
+				outfile.write("<table align=\"center\"><tr>");
+			    }
+			
+			if(!(mapFreq==0)){
+			    if(i%7 == 0)
+				outfile.write("</tr><tr>");
+			    outfile.write("<td align=\"center\">"+link+thumb+"</a><br>"+link+year+"</a></td>");
+			}
+			
+			if(i == request_nodes.getLength()-1){
+			    outfile.write("</tr></table><p>");
+			    outfile.flush();
+			    outfile.close();
+			}
+		    }
+		} 
+		
+	    }
+	}catch(IOException ioe){ioe.printStackTrace();}
+	
+	return result;
+	}catch(Exception excep){excep.printStackTrace();}
+	return null;
+
+    }
+
+    protected Element processDocumentContentRetrieve(Element request){
+	// Create a new (empty) result message
+	Element result = doc.createElement(GSXML.RESPONSE_ELEM);
+	result.setAttribute(GSXML.FROM_ATT, DOCUMENT_CONTENT_RETRIEVE_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+	
+	String uid = request.getAttribute(GSXML.USER_ID_ATT);
+	String temp_image_file = this.temp_files_dir+"temp_"+uid+".jpg";
+	String temp_image_file2 = this.temp_files_dir+"temp_"+uid+"_2.jpg";
+
+	Element query_doc_list = (Element) GSXML.getChildByTagName(request, GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	if (query_doc_list == null) {
+	    logger.error("DocumentContentRetrieve request specified no doc nodes.\n");
+	    return result;
+	}
+	
+	String legend_file = this.temp_files_dir+"legend_"+uid+".jpg";
+	String blank_file = this.files_home_dir + "blank.jpg";
+	Element doc_list = doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(doc_list);
+	
+	// Get the documents
+	String[] doc_ids = GSXML.getAttributeValuesFromList(query_doc_list, 
+							     GSXML.NODE_ID_ATT);
+
+	for (int i = 0; i < doc_ids.length; i++) {
+	    String doc_id = doc_ids[i];
+	    // img_num is the name of the map file eg. 072.jpg
+	    String img_num = doc_id.substring(0,doc_id.indexOf('.'));
+	    // strings for inserting image in html
+	    String img_left = "<img border=0 src=\""+this.http_temp_image_dir;
+	    String doc_content = "";
+	    String co_ordinates = "";
+	    String img_size = "";
+	    int height = 0;
+	    int width = 0;
+	    // the number for the legend image if adding locations to the map
+	    int leg_num = 0;
+	    double ratio = 0;
+
+	    // if user has clicked on the map.  This does not resolve maps that are not North oriented.
+	    if(doc_id.indexOf("imageChooser")==0){
+		try{
+		    doc_id = doc_id.substring(doc_id.indexOf('`')+1,doc_id.length());
+		    img_num = doc_id.substring(0,doc_id.indexOf('.'));
+
+		    // get the map size
+		    String get_size[] = {"identify","-size","10000", temp_image_file};
+		    Process proc;
+		    proc = Runtime.getRuntime().exec(get_size);
+		    BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+		    img_size = br.readLine();
+		    proc.waitFor();
+		    img_size = img_size.substring(img_size.indexOf("JPEG")+5,img_size.indexOf(" ",img_size.indexOf("JPEG")+5));
+		    width = Integer.parseInt(img_size.substring(0,img_size.indexOf("x")));
+		    height = Integer.parseInt(img_size.substring(img_size.indexOf("x")+1,img_size.length()));
+
+		    // scale image size according to the ratio
+		    ratio = Double.parseDouble(doc_id.substring(doc_id.lastIndexOf('`',doc_id.indexOf("```")-1)+1,doc_id.indexOf("```")));
+		    width = (int)(width*ratio);
+		    height = (int)(height*ratio);
+
+		    // get the position of the mouse click on the image
+		    int xclick = Integer.parseInt(doc_id.substring(doc_id.indexOf("```")+3,doc_id.lastIndexOf('`')));
+		    int yclick = Integer.parseInt(doc_id.substring(doc_id.lastIndexOf('`')+1,doc_id.length()));
+		    doc_id = doc_id.substring(doc_id.indexOf('`')+1,doc_id.indexOf("```"));
+
+		    // convert click position to percentage distance accross and down the image.
+		    double xpercent = (xclick*1.0)/width;
+		    double ypercent = (yclick*1.0)/height;
+
+		    // get the top left and bottom right co-ordinates of the map
+		    double ytop = Double.parseDouble(doc_id.substring(0,doc_id.indexOf('`')))*-1;
+		    doc_id = doc_id.substring(doc_id.indexOf('`')+1,doc_id.length());
+		    double xleft = Double.parseDouble(doc_id.substring(0,doc_id.indexOf('`')));
+		    doc_id = doc_id.substring(doc_id.indexOf('`')+1,doc_id.length());
+		    double ybot = Double.parseDouble(doc_id.substring(0,doc_id.indexOf('`')))*-1;
+		    doc_id = doc_id.substring(doc_id.indexOf('`')+1,doc_id.length());
+		    double xright = Double.parseDouble(doc_id.substring(0,doc_id.indexOf('`')));
+		    doc_id = doc_id.substring(doc_id.indexOf('`')+1,doc_id.length());
+
+		    // calculate the map co-ordinates of the mouse click
+		    xpercent = ((xright-xleft)*xpercent)+xleft;
+		    ypercent = ((ybot-ytop)*ypercent)+ytop;
+
+		    // search the tree for nearby place names
+		    namesInList.clear();
+		    findName(xpercent, ypercent, 0.1, 0.1, tree, true);
+
+		    int namesInArraySize = namesInList.size();
+		    String returnNames[]=new String[namesInArraySize];
+
+		    //put the names in an array
+		    for(int ri=0; namesInList.size()>0; ri++){
+			returnNames[ri]=(String)namesInList.getFirst();
+			returnNames[ri] = returnNames[ri].substring(0,returnNames[ri].indexOf('`'));
+			namesInList.removeFirst();
+		    }
+
+		    //sort the names
+		    Arrays.sort(returnNames);
+		    doc_content = "\n<script>\nfunction openIt(loc){\n\topener.location=loc;\n\tself.close();\n}\n</script>";
+		    for(int nameIndex=0; nameIndex < namesInArraySize; nameIndex++){
+			String tempName = returnNames[nameIndex];
+			//convert names with spaces for hyperlinks
+			if(returnNames[nameIndex].indexOf(' ') != -1){
+			    returnNames[nameIndex] = returnNames[nameIndex].replaceAll(" ","+");
+			    returnNames[nameIndex] = "%22"+returnNames[nameIndex]+"%22";
+			}
+			// add the place name to the html
+			doc_content = doc_content+"<a href=\"\" onClick=openIt('?a=q&sa=&rt=r&s=MapQuery&c="+this.cluster_name+"&startPage=1&s1.index=none&s1.maxDocs=10&s1.query="+returnNames[nameIndex]+"')>"+tempName+"</a><br>";
+		    }
+		    
+		}catch(Exception ioexception){ioexception.printStackTrace();}
+	    }
+	    else{
+		
+		try{
+		    //file for converting image    
+		    BufferedWriter bw = new BufferedWriter(new FileWriter(this.temp_files_dir + "add_x_"+uid));;
+		    Process proc;
+		    
+		    // if a new search
+		    if(doc_id.indexOf("```") != -1){
+			// copy requested map to temp.jpg
+			proc = Runtime.getRuntime().exec("cp "+this.files_home_dir+"maps"+File.separator+img_num+".jpg "+temp_image_file);
+			proc.waitFor();
+		    }
+
+		    //get the image size
+		    String get_size[] = {"identify","-size","10000", temp_image_file};
+		    proc = Runtime.getRuntime().exec(get_size);
+		    BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+		    img_size = br.readLine();
+		    proc.waitFor();
+		    img_size = img_size.substring(img_size.indexOf("JPEG")+5,img_size.indexOf(" ",img_size.indexOf("JPEG")+5));
+		    if (img_size.indexOf("+")!=-1) {
+			img_size = img_size.substring(0, img_size.indexOf("+"));
+		    }
+		    width = Integer.parseInt(img_size.substring(0,img_size.indexOf("x")));
+		    height = Integer.parseInt(img_size.substring(img_size.indexOf("x")+1,img_size.length()));
+		    
+		    // if a new search
+		    if(doc_id.indexOf("```") != -1){
+			co_ordinates = doc_id.substring(doc_id.indexOf("```")+2, doc_id.length());
+			// get the number of places to mark on the map
+			int x_number = Integer.parseInt(doc_id.substring(doc_id.lastIndexOf('`',doc_id.indexOf("```")-1)+1,doc_id.indexOf("```")));
+
+			//write the convert command
+			bw.write("convert -font helvetica -fill red -pointsize 48 ");
+
+			for(int xi=0; xi<x_number; xi++){
+
+			    // get the co-ordinates of the place name
+			    double xco = Double.parseDouble(co_ordinates.substring(co_ordinates.lastIndexOf('`',co_ordinates.lastIndexOf('`')-1)+1,co_ordinates.lastIndexOf('`',co_ordinates.lastIndexOf('`')-1)+7));
+			    double yco = Double.parseDouble(co_ordinates.substring(co_ordinates.lastIndexOf('`')+1,co_ordinates.length()));
+			    if(xi != x_number-1)
+				co_ordinates = co_ordinates.substring(0,co_ordinates.lastIndexOf('`',co_ordinates.lastIndexOf('`')-1));
+			
+			    int index = 0;
+			    index = doc_id.indexOf('`')+2;
+			    
+			    // get the zoom ratio and the top left and bottom right co-ordinates of the map
+			    ratio = 0.4;
+			    double tly = Double.parseDouble(doc_id.substring(index,index+5));
+			    index = doc_id.indexOf('`',index)+1;
+			    double tlx = Double.parseDouble(doc_id.substring(index,index+6));
+			    index = doc_id.indexOf('`',index)+2;
+			    double bry = Double.parseDouble(doc_id.substring(index,index+5));
+			    index = doc_id.indexOf('`',index)+1;
+			    double brx = Double.parseDouble(doc_id.substring(index,index+6));
+			    index = doc_id.indexOf('`',index)+1;
+			    double orient = Double.parseDouble(doc_id.substring(index,doc_id.indexOf('`',index)));
+
+			    // find the centre of the map
+			    double xcent = ((brx-tlx)/2)+tlx;
+			    double ycent = ((bry-tly)/2)+tly;
+
+			    // get the orientation of the map
+			    orient = Math.toRadians(orient);
+
+			    // rotate the co-ordinates around the centre of the map 
+			    xco=xco-xcent;
+			    yco=yco-ycent;
+			    double oldx=xco;
+			    xco=xco*Math.cos(orient)-yco*Math.sin(orient);
+			    yco=oldx*Math.sin(orient)+yco*Math.cos(orient);
+			    xco=xco+xcent;
+			    yco=yco+ycent;
+			    xco = (xco-tlx)/(brx-tlx);
+			    yco = (yco-tly)/(bry-tly);
+
+			    // calculate the pixels for placing the mark
+			    width = (int)(xco*width)-5;
+			    height = (int)(yco*height)-5;
+			
+			    // write the options for convert
+			    bw.write("-draw 'text "+width+","+height+" \"x\"' ");
+			    bw.flush();
+			
+			    // reset the width and height variables for the image
+			    width = Integer.parseInt(img_size.substring(0,img_size.indexOf("x")));
+			    height = Integer.parseInt(img_size.substring(img_size.indexOf("x")+1,img_size.length()));
+			}
+			doc_id = doc_id.substring(0,doc_id.lastIndexOf('`',doc_id.indexOf("```")-1));
+
+			// write the end of the convert command, then command for zooming image to the right level, then command to copy the blank image over legend.jpg
+			bw.write(temp_image_file+" "+temp_image_file+";convert -scale "+((int)(ratio*width))+"x"+((int)(ratio*height))+" "+temp_image_file+" "+temp_image_file2+";cp "+blank_file +" "+legend_file);
+
+			// reset legend number
+			leg_num = 0;
+		    }
+
+		    else
+			// if changing zoom level
+			if(doc_id.substring(doc_id.lastIndexOf('`'),doc_id.length()).indexOf('.')!=-1){
+			    // get the ratio
+			    ratio = Double.parseDouble(doc_id.substring(doc_id.lastIndexOf('`')+1,doc_id.length()));
+			    // write the command for scaling image
+			    bw.write("convert -scale "+((int)(ratio*width))+"x"+((int)(ratio*height))+" "+temp_image_file+" "+temp_image_file2);
+			    doc_id = doc_id.substring(0,doc_id.lastIndexOf('`'));
+			}
+
+		        // if adding locations to map
+			else{
+
+			    // get the location type to add
+			    String restricter= doc_id.substring(doc_id.lastIndexOf('`')+1,doc_id.length());
+			    doc_id = doc_id.substring(0,doc_id.lastIndexOf('`'));
+
+			    // get the number for the legend image
+			    leg_num = Integer.parseInt(doc_id.substring(doc_id.lastIndexOf('`')+1,doc_id.length()));
+			    doc_id = doc_id.substring(0,doc_id.lastIndexOf('`'));
+
+			    //open file for location type
+			    BufferedReader inType = new BufferedReader(new FileReader(this.files_home_dir + "place_types"+File.separator + restricter + ".txt"));
+
+			    //check through the file and add any places that are in the bounds of this map.
+
+			    // check value. set to true if a place to add is found
+			    boolean add_place_type = false;
+
+			    int index = 0;
+			    index = doc_id.indexOf('`')+2;
+			    // get zoom ratio
+			    ratio = Double.parseDouble(doc_id.substring(doc_id.lastIndexOf('`')+1,doc_id.length()));
+			    // get top left and bottom right co-ordinates of the map
+			    double tly = Double.parseDouble(doc_id.substring(index,index+5));
+			    index = doc_id.indexOf('`',index)+1;
+			    double tlx = Double.parseDouble(doc_id.substring(index,index+6));
+			    index = doc_id.indexOf('`',index)+2;
+			    double bry = Double.parseDouble(doc_id.substring(index,index+5));
+			    index = doc_id.indexOf('`',index)+1;
+			    double brx = Double.parseDouble(doc_id.substring(index,index+6));
+			    index = doc_id.indexOf('`',index)+1;
+			    // get orientation of the map
+			    double orient = Double.parseDouble(doc_id.substring(index,doc_id.indexOf('`',index)));
+			    // calculate centre of map
+			    double xcent = ((brx-tlx)/2)+tlx;
+			    double ycent = ((bry-tly)/2)+tly;
+			    orient = Math.toRadians(orient);
+
+			    String type_point = "";
+			    double xco = 0.0;
+			    double yco = 0.0;
+
+			    // read the file
+			    while(inType.ready()){
+				//read a line
+				type_point = inType.readLine();
+
+				// get the co-ordinates of the point
+				xco = Double.parseDouble(type_point.substring(type_point.lastIndexOf('`')+1,type_point.length()));
+				yco = Double.parseDouble(type_point.substring(type_point.lastIndexOf('`',type_point.lastIndexOf('`')-1)+2,type_point.lastIndexOf('`')));
+
+				// if it is within the co-ordinates of the map
+				if(xco >= tlx && xco < brx && yco >= tly && yco < bry){
+				    // rotate the point around the centre according to map orientation
+				    xco=xco-xcent;
+				    yco=yco-ycent;
+				    double oldx=xco;
+				    xco=xco*Math.cos(orient)-yco*Math.sin(orient);
+				    yco=oldx*Math.sin(orient)+yco*Math.cos(orient);
+				    xco=xco+xcent;
+				    yco=yco+ycent;
+				    // get the pixels for where to place the mark
+				    xco = (xco-tlx)/(brx-tlx);
+				    yco = (yco-tly)/(bry-tly);
+				    width = (int)(xco*width)-5;
+				    height = (int)(yco*height)-5;
+
+				    //if this is the first point to be added
+				    if(!add_place_type){
+					// write the initial convert command
+					bw.write("convert -font helvetica -fill red -pointsize 36 ");
+					// toggle check value
+					add_place_type = true;
+				    }
+
+				    // write the options for the convert command
+				    bw.write("-draw 'text "+width+","+height+" \""+leg_num+"\"' ");
+				    bw.flush();
+			
+				    // reset width and height variables for the image
+				    width = Integer.parseInt(img_size.substring(0,img_size.indexOf("x")));
+				    height = Integer.parseInt(img_size.substring(img_size.indexOf("x")+1,img_size.length()));
+				}
+			    }
+
+			    //if there are places to mark on the map
+			    if(add_place_type){
+				// finish the convert command and write command for scaling image
+				bw.write(temp_image_file+" "+temp_image_file+";convert -scale "+((int)(ratio*width))+"x"+((int)(ratio*height))+" "+temp_image_file+" "+temp_image_file2);
+
+				// open file for converting the legend command
+				BufferedWriter buf = new BufferedWriter(new FileWriter(this.temp_files_dir+"add_l_"+uid));
+				if(leg_num == 1)
+				    buf.write("cp "+blank_file +" "+legend_file+";");
+				// write the command for adding to the legend
+				buf.write("convert -font helvetica -fill red -pointsize 12 -draw 'text 15,"+(leg_num*15+20)+" \""+leg_num+" "+getType(restricter)+"\"' "+legend_file+" "+legend_file);
+				buf.flush();
+				buf.close();
+				// execute the command for the legend image
+				proc = Runtime.getRuntime().exec("sh "+this.temp_files_dir+"add_l_"+uid);
+				proc.waitFor();
+			    }
+			    inType.close();
+			}
+		    bw.flush();
+		    bw.close();
+		
+		    // execute the convert commands etc.
+		    proc = Runtime.getRuntime().exec("sh "+this.temp_files_dir+"add_x_"+uid);
+		    proc.waitFor();
+		
+		}catch(Exception ioe){ioe.printStackTrace();}
+
+		//write the html for the document
+
+		String doc_content_head = "?a=d&c="+this.cluster_name+"&dt=map&d=";
+		doc_content = "<td valign=\"top\"><script>document.write('"+img_left+"legend_"+uid+".jpg"+"?'+new Date().getTime())</script>\"></td>";
+		doc_content = doc_content+"<td><script>document.write('"+img_left+"temp_"+uid+"_2.jpg?'+new Date().getTime())</script>\" onclick=\"imgClickHandler(event, this, '"+img_num+"')\"></td>";
+
+		// replace _httpimg_ with the correct address
+		doc_content = "<table><tr>"+doc_content+"</tr></table>";
+
+		String javascript = getJavascript(ratio, doc_id, leg_num);
+
+		doc_content = "<center>You are currently viewing the map at "+(int)(ratio*100)+"%<br>Select a radio button for a new zoom level.</center>"+javascript+doc_content;
+		doc_content = doc_content.replaceAll("zoomhead", doc_content_head);
+		doc_content = doc_content.replaceAll("placeChooserImage", doc_content_head+"imageChooser`"+doc_id+"`"+ratio);
+
+		// read the file for the navigation thumbnails
+		try{
+		    BufferedReader infile = new BufferedReader(new FileReader(this.temp_files_dir+"links"+uid));
+		    doc_content = doc_content + infile.readLine();
+		    infile.close();
+		}catch(Exception ioexc){ioexc.printStackTrace();}
+	    }
+
+	    // put the html in a text node
+	    Element text_doc = doc.createElement(GSXML.DOC_NODE_ELEM);
+	    text_doc.setAttribute(GSXML.NODE_ID_ATT, doc_id);
+	    GSXML.addDocText(doc, text_doc, doc_content);
+	    doc_list.appendChild(text_doc);
+	    
+	}
+        return result;
+    }
+
+    // resolves location codes for places from LINZ database
+    private String getLocation(String location){
+	String read;
+	try{
+	    BufferedReader in = new BufferedReader(new FileReader(this.files_home_dir+"files"+File.separator+"landdist.txt"));
+	    in.readLine();
+	    while(in.ready()){
+		read = in.readLine();
+		if(read.substring(0,2).equals(location)){
+		    in.close();
+		    return read.substring(3, read.length());
+		}
+	    }
+	}catch(Exception e){}
+	return "";
+    }
+
+    // resolves type codes for the LINZ database
+    private String getType(String type){
+	String read;
+	try{
+	    BufferedReader in = new BufferedReader(new FileReader(this.files_home_dir+"files"+File.separator+"pointdes.txt"));
+	    in.readLine();
+	    while(in.ready()){
+		read = in.readLine();
+		if(read.substring(0,read.indexOf('`')).toLowerCase().equals(type.toLowerCase())){
+		    in.close();
+		    return read.substring(read.indexOf('`')+1, read.indexOf(':'));
+		}
+	    }
+	}catch(Exception e){}
+	return "";
+    }
+
+    //recursive pre-order traversal of the 2-dimensional tree
+    // x & y are co-ordinates of mouse click, xoff & yoff are the distance in degrees away from x & y to search,
+    // d is the current node of the tree, xcomp controls whether searching is by x co-ordinate or y co-ordinate.
+    private void findName(double x, double y, double xoff, double yoff, DefaultMutableTreeNode d, boolean xcomp){
+	//if a leaf node return.  All leaf nodes are empty
+	if(d.isLeaf())
+	    return;
+	//get coordinates of the current node
+	double xco = Double.parseDouble(((String)d.getUserObject()).substring(((String)d.getUserObject()).length()-6,((String)d.getUserObject()).length()));
+	double yco = Double.parseDouble(((String)d.getUserObject()).substring(((String)d.getUserObject()).length()-12,((String)d.getUserObject()).length()-7));
+	//if in range
+	if((x-xoff)<xco && (x+xoff)>xco && (y-yoff)<yco && (y+yoff)>yco){
+	    //add to list
+	    namesInList.addFirst((String)d.getUserObject());
+	}
+	//if comparing the x axis
+	if(xcomp){
+	    //if need to search left subtree
+	    if((x-xoff)<xco)
+		findName(x,y,xoff,yoff,(DefaultMutableTreeNode)d.getChildAt(0),!xcomp);
+	    //if need to search right subtree
+	    if((x+xoff)>xco)
+		findName(x,y,xoff,yoff,(DefaultMutableTreeNode)d.getChildAt(1),!xcomp);
+	}
+	else{
+	    //if need to search left subtree
+	    if((y-yoff)<yco)
+		findName(x,y,xoff,yoff,(DefaultMutableTreeNode)d.getChildAt(0),!xcomp);
+	    //if need to search right subtree
+	    if((y+yoff)>yco)
+		findName(x,y,xoff,yoff,(DefaultMutableTreeNode)d.getChildAt(1),!xcomp);
+	}
+    }
+
+    // a whole lot of stuff for the html that is hidden at the bottom here because it clutters more than I already have further up!
+    private String getJavascript(double ratio, String doc_id, int leg_num)
+    {
+	String javascript = "\n<script>\nfunction imgClickHandler (evt, img, num) {\n\tif (window.event){\n\t\tvar chooserString = 'placeChooserImage' + '```' + window.event.offsetX + '`' + window.event.offsetY\n\t\tmywindow = window.open(chooserString,'Choose','width=600, height=500, scrollbars=yes, resizable=yes, toolbar=no, location=no, status=yes, menubar=no');\n\t\t//alert(window.event.offsetX + ':' + window.event.offsetY + ':' + num);\n\t}\n\telse if (evt.target) {\n\t\tvar coords = {x: 0, y: 0 };\n\t\tvar el = evt.target;\n\t\tdo {\n\t\t\tcoords.x += el.offsetLeft;\n\t\t\tcoords.y += el.offsetTop;\n\t\t}\n\t\twhile ((el = el.offsetParent));\n\t\tvar offsetX = evt.clientX - coords.x;\n\t\tvar offsetY = evt.clientY - coords.y;\n\t\talert(offsetX + ':' + offsetY + ':' + num);\n\t}\n}\nfunction leapTo (link)\n{\n\tvar new_url=link;\n\tif (  (new_url != \"\")  &&  (new_url != null)  ) \n\t\twindow.location=new_url;\n\telse \n\t\talert(\"You must make a selection.\");\n}\nfunction jumpTo (front,link,back)\n{\n\tvar new_url=front+link+back;\n\tif (  (new_url != \"\")  &&  (new_url != null)  ) \n\t\twindow.location=new_url;\n\telse \n\t\talert(\"You must make a selection.\");\n}// Deactivate Cloaking -->\n</script>";
+
+	String radioButtons = "\n<center><FORM>";
+	if(ratio != 0.4)
+	    radioButtons = radioButtons + "\n\t<INPUT TYPE=\"radio\" NAME=\"buttons1\" onClick=\"leapTo('zoomhead"+doc_id+"`0.4')\">40%";
+	if(ratio != 0.5)
+	    radioButtons = radioButtons + "\n\t<INPUT TYPE=\"radio\" NAME=\"buttons1\" onClick=\"leapTo('zoomhead"+doc_id+"`0.5')\">50%";
+	if(ratio != 0.6)
+	    radioButtons = radioButtons + "\n\t<INPUT TYPE=\"radio\" NAME=\"buttons1\" onClick=\"leapTo('zoomhead"+doc_id+"`0.6')\">60%";
+	if(ratio != 0.7)
+	    radioButtons = radioButtons + "\n\t<INPUT TYPE=\"radio\" NAME=\"buttons1\" onClick=\"leapTo('zoomhead"+doc_id+"`0.7')\">70%";
+	if(ratio != 0.8)
+	    radioButtons = radioButtons + "\n\t<INPUT TYPE=\"radio\" NAME=\"buttons1\" onClick=\"leapTo('zoomhead"+doc_id+"`0.8')\">80%";
+	if(ratio != 0.9)
+	    radioButtons = radioButtons + "\n\t<INPUT TYPE=\"radio\" NAME=\"buttons1\" onClick=\"leapTo('zoomhead"+doc_id+"`0.9')\">90%";
+	if(ratio != 1.0)
+	    radioButtons = radioButtons + "\n\t<INPUT TYPE=\"radio\" NAME=\"buttons1\" onClick=\"leapTo('zoomhead"+doc_id+"`1.0')\">100%";
+	radioButtons = radioButtons + "\n</FORM></center>";
+
+	leg_num = leg_num+1;
+
+	String doc_link = "?a=d&c="+this.cluster_name+"&dt=map&d="+doc_id+"`"+ratio+"`"+leg_num+"`";
+
+	StringBuffer dropDownBox = new StringBuffer();
+
+	dropDownBox.append("Add Locations Of Type: <form name=\"myForm\"><select name=\"s1index\" onChange=\"jumpTo('");
+	dropDownBox.append(doc_link);
+	dropDownBox.append("',document.myForm.s1index.options[document.myForm.s1index.selectedIndex].value,'')\">\n");
+
+	for (int i=0; i<this.index_name_list.size(); i++) {
+	    String name = (String)this.index_name_list.get(i);
+	    dropDownBox.append("<option value=\"");
+	    dropDownBox.append(name);
+	    dropDownBox.append("\">");
+	    String display = (String)this.index_display_list.get(i);
+	    dropDownBox.append(display);
+	    dropDownBox.append("\n");
+	}
+	// for each option, Malcolm had onClick=\"leapTo('"+doc_link+name+"')\" - dont seem to need this
+	dropDownBox.append("</select></form>\n");
+
+	return javascript + radioButtons + dropDownBox;
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/MapSearch.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/MapSearch.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/MapSearch.java	(revision 14125)
@@ -0,0 +1,394 @@
+/*
+ *    MapSearch.java
+ *    Copyright (C) 2005 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.service;
+
+// Greenstone classes
+import org.greenstone.gsdl3.util.*;
+
+// XML classes
+import org.w3c.dom.Element; 
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList; 
+
+// General java classes
+import java.util.Hashtable;
+import java.util.HashMap;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.lang.reflect.Array;
+import java.util.Comparator;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.FileInputStream;
+import java.lang.ClassNotFoundException;
+
+import org.apache.log4j.*;
+
+/**
+ *
+ * 
+ */
+public class MapSearch 
+    extends AbstractSearch {
+
+
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.MapSearch.class.getName());
+
+    protected String files_home_dir = null;
+
+    protected static final String FREQ_ATT = "freq";
+
+    // use the following if we add back in index searching
+    //protected String default_index = null;
+    //protected static final String DEFAULT_INDEX_ELEM = "defaultIndex";
+    //protected static final String INDEX_ELEM = "index";  
+    
+    /** Hashtable containing the place names database, indexed on the place name in lower case. */
+    public static Hashtable hashNames;
+
+    /** Constructor */
+    public MapSearch() {}
+
+    /** */
+    public boolean configure(Element info, Element extra_info)
+    {
+	if (!super.configure(info, extra_info)) {
+	    return false;
+	}
+	logger.info("Configuring MapSearch...");
+
+	// set the files_home_dir variable for this collection
+	this.files_home_dir = GSFile.collectionIndexDir(site_home, cluster_name)+File.separator+"assoc"+File.separator;
+
+	//load the hashtable
+	hashNames = new Hashtable();
+	try{
+	    ObjectInputStream in = new ObjectInputStream(new FileInputStream(this.files_home_dir+"hashnames.dat"));
+	    hashNames = (Hashtable)in.readObject();
+	    in.close();
+	}catch(IOException ioe){
+	    ioe.printStackTrace();
+	    return false;
+	}catch(ClassNotFoundException cnf){
+	    cnf.printStackTrace();
+	    return false;
+	}
+	 
+	// just in case we get the index stuff going, here is the code
+	
+	// get the display stuff for the indexes
+	
+// 	NodeList indexes = info.getElementsByTagName(GSXML.INDEX_ELEM);
+// 	if (extra_info != null) {
+// 	    Document owner = info.getOwnerDocument();
+// 	    Element config_search = (Element)GSXML.getChildByTagName(extra_info, GSXML.SEARCH_ELEM);
+// 	    if (config_search != null) {
+// 		for (int i=0; i<indexes.getLength();i++) {
+// 		    Element ind = (Element)indexes.item(i);
+// 		    String name = ind.getAttribute(GSXML.NAME_ATT);
+// 		    Element node_extra = GSXML.getNamedElement(config_search,
+// 							       GSXML.INDEX_ELEM,
+// 							       GSXML.NAME_ATT,
+// 							       name);
+// 		    if (node_extra == null) {
+// 			// no index specification for this index
+// 			continue;
+// 		    }
+		    
+// 		    // get the display elements if any - displayName
+// 		    NodeList display_names = node_extra.getElementsByTagName(GSXML.DISPLAY_TEXT_ELEM);
+// 		    if (display_names !=null) {
+// 			for (int j=0; j<display_names.getLength(); j++) {
+// 			    Element e = (Element)display_names.item(j);
+// 			    ind.appendChild(owner.importNode(e, true));
+// 			}
+// 		    }
+// 		} // for each index
+// 	    }
+// 	}
+// 	// Get the default index out of <defaultIndex> (buildConfig.xml)
+// 	Element def = (Element) GSXML.getChildByTagName(info, DEFAULT_INDEX_ELEM);
+// 	if (def != null) {
+// 	    default_index = def.getAttribute(GSXML.NAME_ATT);
+// 	}
+// 	if (default_index == null || default_index.equals("")) {
+// 	    // use the first one from the index list
+// 	    default_index = ((Element)indexes.item(0)).getAttribute(GSXML.NAME_ATT);
+// 	}
+
+	return true;
+    }
+
+    protected void getIndexData(ArrayList index_ids, ArrayList index_names, String lang) 
+    {
+	// for now, we just have one dummy index
+	index_ids.add("idx");
+	index_names.add("maps"); // get from properties
+
+	// use the following if we ever get the index search working
+// 	Element index_list = (Element)GSXML.getChildByTagName(this.config_info, INDEX_ELEM+GSXML.LIST_MODIFIER);
+// 	NodeList indexes = index_list.getElementsByTagName(INDEX_ELEM);
+// 	for (int i=0; i<indexes.getLength(); i++) {
+// 	    Element index = (Element)indexes.item(i);
+// 	    index_ids.add( index.getAttribute(GSXML.NAME_ATT));
+// 	    index_names.add(GSXML.getDisplayText(index, GSXML.DISPLAY_TEXT_NAME, lang, "en"));
+		
+// 	}
+    }
+    
+
+    /** Process a map query */
+    protected Element processTextQuery(Element request) 
+    {
+	// Create a new (empty) result message
+	Element result = doc.createElement(GSXML.RESPONSE_ELEM);
+	result.setAttribute(GSXML.FROM_ATT, TEXT_QUERY_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+
+	// Get the parameters of the request
+	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (param_list == null) {
+	    logger.error("TextQuery request had no paramList.");
+	    return result;  // Return the empty result
+	}
+
+	// Process the request parameters
+	HashMap params = GSXML.extractParams(param_list, false);
+
+	// Make sure a query has been specified
+	String searchTerm = (String) params.get(QUERY_PARAM);
+	if (searchTerm == null || searchTerm.equals("")) {
+	    return result;  // Return the empty result
+	}
+
+	// If an index hasn't been specified, use the default
+// 	String index = (String) params.get(INDEX_PARAM); 
+// 	if (index == null) {
+// 	    index = default_index;
+// 	}
+
+	//convert the query string from the form '&quotTe Awamutu&quot Hamilton' to 'Te Awamutu+Hamilton'
+
+	//replace ' ' with '+'
+	searchTerm = searchTerm.replace(' ','+');
+
+	//replace '&quot' with '"'
+	int place = -1;
+	while(searchTerm.indexOf("&quot;",place+1) != -1){
+	    place = searchTerm.indexOf("&quot;",place+1);
+	    searchTerm = (searchTerm.substring(0,place) + "\"" + searchTerm.substring(place+6,searchTerm.length()));
+	}
+
+	//replace spaces in string enclosed in quotes
+	place = -1;
+	while(searchTerm.indexOf('"',place+1) != -1){
+	    place = searchTerm.indexOf('"',place+1);
+	    if(searchTerm.indexOf('"',place+1) != -1)
+		searchTerm = (searchTerm.substring(0,place) + searchTerm.substring(place, searchTerm.indexOf('"',place+1)).replace('+',' ') + searchTerm.substring(searchTerm.indexOf('"',place+1), searchTerm.length()));
+	    place = searchTerm.indexOf('"',place);
+	}
+
+	//remove speech marks
+	place = 0;
+	while(place != -1){
+	    place = searchTerm.indexOf('"', place);
+	    if(place != -1){
+		searchTerm = searchTerm.substring(0, place) + searchTerm.substring(place+1, searchTerm.length());
+		place=0;
+	    }
+	}
+
+	//find the number of search terms (number of '+' plus 1)
+	int words = 1;
+	place = 0;
+	while (place != -1){
+	    place = searchTerm.indexOf('+', place+1);
+	    if(place != -1) words++;
+	}
+	place = 0;
+
+	//store each search term in a string array
+	String terms[] = new String[words];
+	String terms_freq[] = new String[words];
+	for (int i=0; i<(words-1); i++){
+	    terms[i]=searchTerm.substring(place, searchTerm.indexOf('+', place));
+	    place = searchTerm.indexOf('+', place)+1;
+	}
+	terms[words-1] = searchTerm.substring(place, searchTerm.length());
+
+	Object nameArray[] = new Object[1];
+	int nameArraySize;
+	String nameData;
+	double xco, yco;
+	LinkedList mapList = new LinkedList();
+	LinkedList placeList = new LinkedList();
+	String readString = "";
+
+	//capitalise the search terms
+	for(int i=0;i<words;i++)
+	    terms[i] = terms[i].toUpperCase();
+
+	for(int k=0; k<words; k++){
+	    nameArraySize=0;
+
+
+	    if((nameArray = (Object[])hashNames.get(terms[k].toLowerCase())) != null){
+		logger.debug(hashNames.get(terms[k].toLowerCase()));
+		
+		nameArraySize = Arrays.asList(nameArray).size();
+	    }
+	    
+	    
+	    int h;
+	    for(h=0;h<nameArraySize;h++){
+
+		nameData = (String)nameArray[h];
+
+		// get the co-ordinates of the current place name
+		xco = Double.parseDouble(nameData.substring(nameData.lastIndexOf('`')+1,nameData.length()));
+		yco = Double.parseDouble(nameData.substring(nameData.lastIndexOf('`',nameData.lastIndexOf('`')-1)+2,nameData.lastIndexOf('`')));
+
+		//open the text file containing map metadata (first line is a description of the file)
+		try{
+		    BufferedReader inmap = new BufferedReader(new FileReader(this.files_home_dir + "files"+File.separator+"maps"+File.separator+"mapdata.txt"));
+		    inmap.readLine();
+
+		    // for each map
+		    while(inmap.ready()){
+			readString = inmap.readLine();
+			int indexer = 0;
+			indexer = readString.indexOf('`')+2;
+			// get the co-ordinates of the top left and bottom right corners of the map.
+			double ytop = Double.parseDouble(readString.substring(indexer,indexer+5));
+			indexer = readString.indexOf('`',indexer)+1;
+			double xtop = Double.parseDouble(readString.substring(indexer,indexer+6));
+			indexer = readString.indexOf('`',indexer)+2;
+			double ybot = Double.parseDouble(readString.substring(indexer,indexer+5));
+			indexer = readString.indexOf('`',indexer)+1;
+			double xbot = Double.parseDouble(readString.substring(indexer,indexer+6));
+
+			//if the place is within the map, put the map metadata and the placename metadata in linked list
+			if(xco >= xtop && xco < xbot && yco >= ytop && yco < ybot)
+			    mapList.add(readString+"```"+nameData);
+		    }
+		}catch(Exception e){e.printStackTrace();}
+	    }
+	}
+
+	// use an array object to sort the linked list by map number
+	Object[] mapListArray = mapList.toArray();
+	Arrays.sort(mapListArray);
+	mapList.clear();
+	for(int mla=0; mla<Array.getLength(mapListArray); mla++)
+	    mapList.addFirst(mapListArray[mla]);
+
+	//for each map, create a list of the query matches on that map
+	LinkedList tempList = new LinkedList();
+	String mapNumber = "";
+	String currentMap[] = {"",""};
+	int mapFreq = 0;
+	while(mapList.size()>0){
+	    readString = (String)mapList.removeFirst();
+	    if(mapNumber.equals(readString.substring(0,readString.indexOf('.')))){
+		currentMap[1] = currentMap[1]+readString.substring(readString.indexOf("```"),readString.length());
+		mapFreq++;
+	    }
+	    else{
+		if(!currentMap[0].equals(""))
+		    tempList.add(currentMap[0]+"`"+mapFreq+currentMap[1]);
+		currentMap[0] = readString.substring(0,readString.indexOf("```"));
+		currentMap[1] = readString.substring(readString.indexOf("```"),readString.length());
+		mapNumber = readString.substring(0,readString.indexOf('.'));
+		mapFreq=1;
+	    }
+	}
+	if(!currentMap[0].equals(""))
+	    tempList.add(currentMap[0]+"`"+mapFreq+currentMap[1]);
+
+	int totalDocs = tempList.size();
+
+	// use an array object to sort the linked list by number of matches on each map
+	Object[] tempListArray = tempList.toArray();
+	Arrays.sort(tempListArray, new MapResultSorter());
+	tempList.clear();
+	for(int tla=0; tla<Array.getLength(tempListArray); tla++)
+	    tempList.add(tempListArray[tla]);
+
+	// Create a metadata list to store information about the query results
+	Element metadata_list = doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER); 
+	result.appendChild(metadata_list);
+			
+	// Add a metadata element specifying the number of matching documents
+	GSXML.addMetadata(this.doc, metadata_list, "numDocsMatched", "" + totalDocs);
+	GSXML.addMetadata(this.doc, metadata_list, "numDocsReturned", ""+totalDocs);
+       	// Create a document list to store the matching documents, and add them
+	Element document_list = doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(document_list);
+	for (int d = 0; d < totalDocs; d++) {
+	    String doc_id = (String)tempList.get(d);
+
+	    Element doc_node = doc.createElement(GSXML.DOC_NODE_ELEM);
+	    doc_node.setAttribute(GSXML.NODE_ID_ATT, doc_id);
+	    doc_node.setAttribute(GSXML.NODE_TYPE_ATT, "thumbnail");
+	    doc_node.setAttribute(GSXML.DOC_TYPE_ATT, "map");
+	    document_list.appendChild(doc_node);
+	}
+			
+	// Create a term list to store the term information, and add it
+	Element term_list = doc.createElement(GSXML.TERM_ELEM+GSXML.LIST_MODIFIER);
+	result.appendChild(term_list);	
+	
+
+	for (int t=0; t<words; t++){
+	    String term = terms[t];
+	
+	    Element term_elem = doc.createElement(GSXML.TERM_ELEM);
+  	    term_elem.setAttribute(GSXML.NAME_ATT, term);
+  	    term_elem.setAttribute(FREQ_ATT, "" + terms_freq[t]);
+
+	    term_list.appendChild(term_elem);
+	}
+	return result;
+    }
+ 
+
+    public class MapResultSorter implements Comparator {
+	
+	public int compare(Object o1, Object o2) {
+	    String first = (String)o1;
+	    String second = (String) o2;
+	    int firstInt;
+	    int secondInt;
+	    first = first.substring(first.lastIndexOf('`',first.indexOf("```")-1)+1,first.indexOf("```"));
+	    second = second.substring(second.lastIndexOf('`',second.indexOf("```")-1)+1,second.indexOf("```"));
+	    firstInt = Integer.parseInt(first);
+	    secondInt = Integer.parseInt(second);
+	    if(firstInt > secondInt)
+		return -1;
+	    else if(firstInt == secondInt)
+		return 0;
+	    else
+		return 1;
+	}
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/ModuleWrapper.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/ModuleWrapper.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/ModuleWrapper.java	(revision 14125)
@@ -0,0 +1,240 @@
+/*
+ *    ModuleWrapper.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.service;
+import org.greenstone.gsdl3.core.ModuleInterface;
+
+// XML classes
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.SAXParser;
+import org.apache.xerces.dom.TextImpl;
+import org.apache.xerces.parsers.DOMParser;
+import org.w3c.dom.Document; 
+import org.w3c.dom.Element;
+import org.w3c.dom.Node; 
+import org.w3c.dom.Node;                                                
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+
+// java classes
+import java.io.StringReader;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.security.SecureRandom;
+
+import org.apache.log4j.*;
+
+/**
+ * A classes for logging and checking all traffic to and from a ModuleInterface
+ * 
+ * if logCounter hasn't been initialised, initialise it to a random 
+ * value. This has to use secure random rather than a normal random
+ * or every time the application is run the same numbers will be
+ * generated and the search for a free range will become a linear
+ * search rather than a hash.
+ *
+ *
+ * @author <a href="mailto:s.yeates@cs.waikato.ac.nz">Stuart Yeates</a>
+ * @version $Revision$
+ */
+public class ModuleWrapper 
+  implements ModuleInterface 
+{
+
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service. ModuleWrapper.class.getName());
+
+  /** the module we're wrapping */
+  protected ModuleInterface inner = null;
+  /** the module we're wrapping */
+  public ModuleInterface getInner(){return inner;};
+  /** the module we're wrapping */
+  public void setInner(ModuleInterface i){inner=i;};
+
+  /** The schema of the IN XML */
+  protected String fromSchema = null;
+  /** The schema of the IN XML */
+  public String getFromSchema(){return fromSchema;};
+  /** The schema of the IN XML */
+  public void setFromSchema(String s){fromSchema=s;};
+
+  /** The schema of the OUT XML */
+  protected String toSchema = null;
+  /** The schema of the OUT XML */
+  public String getToSchema(){return toSchema;};
+  /** The schema of the OUT XML */
+  public void setToSchema(String s){toSchema=s;};
+
+  /** Are we logging the XML ? */
+  protected boolean logging = true;
+  /** Are we logging the XML ? */
+  public boolean getLogging(){return logging;};
+  /** Are we logging the XML ? */
+  public void setLogging(boolean b){logging=b;};
+
+  /** Where we are logging the XML */
+  protected String logDirectory = "/tmp/";
+  /** Where we are logging the XML */
+  public String getLogDirectory(){return logDirectory;};
+  /** Where we are logging the XML */
+  public void setLogDirectory(String s){logDirectory=s;};
+
+  /** The number of the previous log file */
+  protected static long logCounter = 0;
+
+  /** The no-args constructor */
+  public ModuleWrapper(){
+
+  }
+  
+  public void cleanUp() {}
+  
+  /** The all-args constructor */
+  public ModuleWrapper(String in,String out, ModuleInterface inner){
+    this.setFromSchema(in);
+    this.setToSchema(out);
+    this.setInner(inner);
+  }
+
+  /**
+   * Process an XML request - as a String
+   *
+   * @param xmlIn the request to process
+   * @return the response - contains any error messages
+   * @see java.lang.String
+   */
+  public String process(String xmlIn) {
+    
+    long logNumber = 0;
+    String xmlOut = "";
+    if (getLogging()) {
+      if (logCounter == 0)
+	logCounter = new SecureRandom().nextLong();
+      try {
+	logNumber = logCounter++;
+	String filename = getLogDirectory() + File.separator + logNumber + ".in";
+	File file = new File(filename);
+	
+	while (file.exists()){
+	  logCounter = new SecureRandom().nextLong();
+	  logNumber = logCounter++;
+	  filename = getLogDirectory() + File.separator + logNumber + ".in";
+	  file = new File(filename);
+	}
+	
+	FileWriter writer = new FileWriter(file);
+	writer.write(xmlIn);
+      } catch (IOException e) {
+	logger.error("caught exception: " +e );
+      }
+    }
+    xmlOut = processInner(xmlIn);
+
+    try {
+      String filename = getLogDirectory() + File.separator + logNumber + ".out";
+      File file = new File(filename);
+      FileWriter writer = new FileWriter(file);
+      writer.write(xmlOut);
+    } catch (IOException e) {
+      logger.error("caught exception: " +e );
+    }
+    return xmlOut;
+  }
+
+  /**
+   * Process an XML request - as a String
+   *
+   * @param xmlIn the request to process
+   * @return the response - contains any error messages
+   * @see java.lang.String
+   */
+  protected String processInner(String xmlIn) 
+  {
+    try {
+      DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
+      DocumentBuilder builder= factory.newDocumentBuilder();
+      DOMParser parser = new DOMParser();
+      try {
+	
+	parser.setFeature("http://xml.org/sax/features/validation",true);
+	parser.setFeature("http://apache.org/xml/features/validation/schema",true);
+	parser.setFeature("http://apache.org/xml/features/validation/dynamic", true);
+	parser.setFeature("http://apache.org/xml/features/validation/schema", true);
+	parser.setFeature("http://apache.org/xml/features/validation/schema-full-checking", true);
+	parser.setFeature("http://apache.org/xml/features/validation/schema/normalized-value", true);
+	parser.setFeature("http://apache.org/xml/features/validation/warn-on-duplicate-attdef", true);
+	parser.setFeature("http://apache.org/xml/features/validation/warn-on-undeclared-elemdef", true);
+	parser.setFeature("http://apache.org/xml/features/warn-on-duplicate-entitydef", true);
+      } catch (Exception a) {
+	logger.error("unable to set feature:" +a);
+	a.printStackTrace();
+      }
+
+      // do the pre-call checking
+      InputSource xml_source = new InputSource(new StringReader(xmlIn));  
+      try {
+	parser.parse(xml_source);
+      } catch (Exception e){  
+	logger.error("parsing error:" +e);
+	e.printStackTrace();
+	return "<response> <error class=\"ModuleWrapper\" code=1> Error: supplied string contained the parse error: " + e + " </error> </response>";
+      } 
+
+      String xmlOut = inner.process(xmlIn);
+
+      // do the post-call checking
+      InputSource xmlResult = new InputSource(new StringReader(xmlIn));  
+      try {
+	parser.parse(xmlResult);
+      } catch (Exception e){  
+	logger.error("parsing error:" +e);
+	e.printStackTrace();
+	return "<response> <error class=\"ModuleWrapper\" code=2> Error: returned string contained the parse error: " + e + "</error></response>";
+      } 
+
+      return xmlOut;
+
+    } catch (Exception e){  
+      logger.error("other error:" +e);
+      e.printStackTrace();
+      return "<response> <error class=\"ModuleWrapper\" code=3>Error: Unknown error or warning: " + e + " </error></response>";
+    } 
+  }
+
+  /**
+   * Process an XML request - as a DOM Element
+   *
+   * @param in the request to process
+   * @return the response - contains any error messages
+   * @see org.w3c.dom.Element
+   */
+  public Element process(Element xmlIn) {
+    throw new Error("Not implmented yet. Should be faked by stringizing the node.");
+  }
+}    
+                                                                           
+
+
+
+
+
+
+
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/PhindPhraseBrowse.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/PhindPhraseBrowse.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/PhindPhraseBrowse.java	(revision 14125)
@@ -0,0 +1,464 @@
+/*
+ *    PhindServices.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.service;
+
+import org.greenstone.gsdl3.util.*;
+
+import org.greenstone.mgpp.*;
+import org.w3c.dom.Document; 
+import org.w3c.dom.Node; 
+import org.w3c.dom.Element; 
+import org.w3c.dom.Text; 
+
+import java.util.Vector;
+import java.util.HashMap;
+import java.io.File;
+
+import org.apache.log4j.*;
+
+/** 
+ * PhindServices - the phind phrase browsing service
+ * 
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @version $Revision$
+ */
+public class PhindPhraseBrowse
+    extends ServiceRack {
+    
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.PhindPhraseBrowse.class.getName());
+
+    // the services on offer
+    private static final String PHIND_SERVICE = "PhindApplet";
+
+    private MGPPWrapper mgpp_src=null;
+    private String basepath = null;
+
+    private Element applet_description = null;
+    
+    public PhindPhraseBrowse() {
+	this.mgpp_src = new MGPPWrapper();
+	// set up the default params
+	this.mgpp_src.setQueryLevel("Document");
+	this.mgpp_src.setReturnLevel("Document");
+	this.mgpp_src.setMaxDocs(5);
+	this.mgpp_src.setStem(false);
+	this.mgpp_src.setCase(true);
+    }
+
+    public void cleanUp() {
+	super.cleanUp();
+	this.mgpp_src.unloadIndexData();
+    }
+
+    /** configure the service module
+     *
+     * @param info a DOM Element containing any config info for the service
+     * @return true if configured
+     */
+    public boolean configure(Element info, Element extra_info) {
+
+	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+
+	logger.info("configuring PhindPhraseBrowse");
+
+	// set up short_service_info_ - for now just has name and type
+	Element e = this.doc.createElement(GSXML.SERVICE_ELEM);
+	e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_APPLET);
+	e.setAttribute(GSXML.NAME_ATT, PHIND_SERVICE);
+	this.short_service_info.appendChild(e);
+
+	// set up the static applet description
+
+	applet_description = this.doc.createElement(GSXML.SERVICE_ELEM);
+	applet_description.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_APPLET);
+	applet_description.setAttribute(GSXML.NAME_ATT, PHIND_SERVICE);
+
+	// add in the applet info for the phind applet
+	// need to make this dynamic - library names etc
+	// change the applet params - have a single param with the library name
+	// this is left blank at this end, and must be filled in by applet action - if the library name is not needed, this param is left out
+	// phindcgi param now is not complete - library must be prepended to it.
+	String app_info = "<"+GSXML.APPLET_ELEM+" CODEBASE='applet' CODE='org.greenstone.applet.phind.Phind.class' ARCHIVE='phind.jar, xercesImpl.jar, xml-apis.jar' WIDTH='500' HEIGHT='400'><PARAM NAME='library' VALUE=''/> <PARAM NAME='phindcgi' VALUE='?";
+	app_info += GSParams.ACTION +"=a&amp;"+GSParams.REQUEST_TYPE +"=r&amp;"+GSParams.SERVICE+"="+PHIND_SERVICE+"&amp;"+GSParams.OUTPUT+"=xml&amp;"+GSParams.RESPONSE_ONLY+"=1'/>";
+	app_info +="<PARAM NAME='collection'   VALUE='";
+	app_info += this.cluster_name;
+	app_info += "'/> <PARAM NAME='classifier' VALUE='1'/>  <PARAM NAME='orientation'  VALUE='vertical'/> <PARAM NAME='depth' VALUE='2'/> <PARAM NAME='resultorder' VALUE='L,l,E,e,D,d'/> <PARAM NAME='backdrop' VALUE='interfaces/default/images/phindbg1.jpg'/><PARAM NAME='fontsize' VALUE='10'/> <PARAM NAME='blocksize'    VALUE='10'/>The Phind java applet.</"+GSXML.APPLET_ELEM+">";
+	
+	Document dom = this.converter.getDOM(app_info);
+	if (dom==null) {
+	    logger.error("Couldn't parse applet info");
+	    return false;
+	}
+	Element app_elem = dom.getDocumentElement();
+	applet_description.appendChild(this.doc.importNode(app_elem, true));
+
+	return true;
+    }
+
+    protected Element getServiceDescription(String service, String lang, String subset) {
+	if (!service.equals(PHIND_SERVICE)) {
+	    return null;
+	}
+	Element describe = (Element) applet_description.cloneNode(true);
+	describe.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_NAME,  getTextString(PHIND_SERVICE+".name", lang)));
+	describe.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_DESCRIPTION,  getTextString(PHIND_SERVICE+".description", lang)));
+	return describe;
+    }
+
+    protected Element processPhindApplet(Element request) {
+	
+	Element param_elem = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	HashMap params = GSXML.extractParams(param_elem, false);
+	
+	long first_e = Long.parseLong((String)params.get("pfe"));
+	long last_e = Long.parseLong((String)params.get("ple"));
+	long first_l = Long.parseLong((String)params.get("pfl"));
+	long last_l = Long.parseLong((String)params.get("pll"));
+	long first_d = Long.parseLong((String)params.get("pfd"));
+	long last_d = Long.parseLong((String)params.get("pld"));
+	
+	long phrase;
+	String phrase_str = (String)params.get("ppnum");
+	if (phrase_str == null || phrase_str.equals("")) {
+	    phrase=0;
+	} else {
+	    phrase = Long.parseLong(phrase_str);
+	}
+	String word = (String)params.get("pptext");
+	String phind_index = (String)params.get("pc");
+	// the location of the mgpp database files
+	this.basepath = GSFile.phindBaseDir(this.site_home, this.cluster_name, phind_index);
+
+	// the result element
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.setAttribute(GSXML.FROM_ATT, PHIND_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+
+	// applet result info must be in appletInfo element
+	Element applet_data = this.doc.createElement(GSXML.APPLET_DATA_ELEM);
+	result.appendChild(applet_data);
+	Element phind_data = this.doc.createElement("phindData");
+	applet_data.appendChild(phind_data);
+
+
+	// if we dont know the phrase number, look it up
+	if (phrase == 0) {
+	    if (word==null || word.equals("")) {
+		Element error = phindError("no word or phrase");
+		phind_data.appendChild(error);
+		return result;
+	    }
+	    phrase = findPhraseNumberFromWord( word);
+	}
+	if (phrase==0) {
+	    // the word is not in the collection
+	    // return a phind error string
+	    Element error = phindError("the term "+word+" is not in the collection");
+	    phind_data.appendChild(error);
+	    return result;
+	}
+	
+	// get the phrase data into the phind_data node
+	getPhraseData(phind_data, phrase, first_l, last_l,
+		      first_e, last_e,  first_d, last_d);
+	return result;
+	
+	
+    }// processPhindApplet
+    
+    protected long findPhraseNumberFromWord(String word) {
+
+	// set the mgpp index data - we are looking up pword
+	this.mgpp_src.loadIndexData(this.basepath+File.separatorChar+"pword");
+
+	this.mgpp_src.runQuery(word);
+
+	MGPPQueryResult res = this.mgpp_src.getQueryResult();
+	Vector docs = res.getDocs();
+	if (docs.size()==0) {
+	    // phrase not found
+	    return 0;
+	}
+	MGPPDocInfo doc = (MGPPDocInfo)docs.firstElement();
+	return doc.num_;
+    }
+
+    protected boolean getPhraseData(Element phind_data,
+				    long phrase, long first_l, long last_l,
+				    long first_e, long last_e, long first_d, 
+				    long last_d) {
+
+	String record = this.mgpp_src.getDocument(this.basepath+File.separatorChar+"pdata", "Document",
+					      phrase);
+	if (record.equals("")) {
+	    Element error = phindError("somethings gone wrong - we haven't got a record for phrase number "+phrase);
+	    phind_data.appendChild(error);
+	    return false;
+	}
+	
+	// parse the record - its in gordons cryptic form
+	// ":word:tf:ef:df:el:dl:lf:ll"
+	// el: e,e,e
+	// dl: d;f,d;f,
+	// lf and ll may be null
+	// l: type,dest, dest; type,dest,dest
+
+	// ignore everything up to and including first colon (has
+	// <Document>3505: at the start)
+	record = record.substring(record.indexOf(':')+1);
+
+	// split on ':'
+	String [] fields = record.split(":");
+	String word = fields[0];
+	String tf = fields[1];
+	String ef = fields[2];
+	String df = fields[3];
+
+	
+	String expansions = fields[4];
+	String documents = fields[5];
+	String lf = "0";
+	String linklist = "";
+	if (fields.length > 7) {// have thesaurus stuff
+	    lf =fields[6];
+	    linklist = fields[7];
+	}
+	
+	// the phindData attributes and phrase
+	phind_data.setAttribute("id", Long.toString(phrase));
+	phind_data.setAttribute("df", df);
+	phind_data.setAttribute("ef", ef);
+	phind_data.setAttribute("lf", lf);
+	phind_data.setAttribute("tf", tf);
+	GSXML.createTextElement(this.doc, "phrase", word);
+
+	addExpansionList(phind_data, expansions, word, ef, first_e, last_e);
+	addDocumentList(phind_data, documents, word, df, first_d, last_d);
+	if (!lf.equals("0")) {
+	    addThesaurusList(phind_data, linklist, word, lf, first_l, last_l);
+	}
+	return true;
+    }
+
+    protected boolean addExpansionList( Element phind_data, String record, 
+				       String word,
+				       String freq,
+				       long first, long last) {
+
+	Element expansion_list = this.doc.createElement("expansionList");
+	phind_data.appendChild(expansion_list);
+	expansion_list.setAttribute("length", freq);
+	expansion_list.setAttribute("start", Long.toString(first));
+	expansion_list.setAttribute("end", Long.toString(last));
+
+	// get the list of strings
+	String [] expansions = record.split(",");
+	int length = expansions.length;
+	if (length < last) last = length;
+	for (long i = first; i < last; i++) {
+	    long num  = Long.parseLong(expansions[(int)i]);
+	    Element expansion = getExpansion( num, word);
+	    expansion.setAttribute("num", Long.toString(i));
+	    expansion_list.appendChild(expansion);
+	}
+	return true;
+    }
+    
+    protected Element getExpansion(long phrase_num, 
+				   String orig_phrase) {
+	
+	// look up the phrase in the pdata thingy
+	String record = this.mgpp_src.getDocument(this.basepath+File.separatorChar+"pdata", "Document",
+					      phrase_num);
+
+	if (record ==null || record.equals("")) return null;
+
+	// ignore everything up to and including first colon 
+	record = record.substring(record.indexOf(':')+1);
+
+	String [] fields = record.split(":");
+	String phrase = fields[0];
+	String tf = fields[1];
+	//String ef = fields[2]; dont use this
+	String df = fields[3];
+
+	Element expansion = this.doc.createElement("expansion");
+	expansion.setAttribute("tf", tf);
+	expansion.setAttribute("df", df);
+	expansion.setAttribute("id", Long.toString(phrase_num));
+
+	// get teh suffix and prefix
+	String [] ends = splitPhraseOnWord(phrase, orig_phrase);
+	if (!ends[0].equals("")) {
+	    expansion.appendChild(GSXML.createTextElement(this.doc, "prefix", ends[0]));
+	}
+	if (!ends[1].equals("")) {
+	    expansion.appendChild(GSXML.createTextElement(this.doc, "suffix", ends[1]));
+	}
+
+	return expansion;
+
+    }
+
+    protected boolean addDocumentList(Element phind_data, String record, 
+				      String word,
+				      String freq,
+				      long first, long last) {
+
+	Element document_list = this.doc.createElement("documentList");
+	phind_data.appendChild(document_list);
+	document_list.setAttribute("length", freq);
+	document_list.setAttribute("start", Long.toString(first));
+	document_list.setAttribute("end", Long.toString(last));
+
+	// get the list of doc,freq
+	String [] doc_freqs = record.split(";");
+	int length = doc_freqs.length;
+	if (length<last) last=length;
+
+	for (long i = first; i < last; i++) {
+	    String doc_elem = doc_freqs[(int)i];
+	    int p = doc_elem.indexOf(',');
+	    long doc_num;
+	    String doc_freq;
+	    if (p == -1) { // there is no freq in the record
+		doc_num =Long.parseLong(doc_elem);
+		doc_freq = "1";
+	    } else {
+		doc_num = Long.parseLong(doc_elem.substring(0,p));
+		doc_freq = doc_elem.substring(p+1);
+	    }
+	    Element document = getDocument( doc_num);
+	    document.setAttribute("freq", doc_freq);
+	    document.setAttribute("num", Long.toString(i));
+	    document_list.appendChild(document);
+	}
+
+	
+	return true;
+    }
+
+
+    protected Element getDocument(long doc_num) {
+	
+	// look up the phrase in the docs thingy
+	String record = this.mgpp_src.getDocument(this.basepath+File.separatorChar+"docs", "Document",
+					      doc_num);
+	
+	if (record ==null || record.equals("")) return null;
+	
+	// ignore everything up to and including first \t
+	record = record.substring(record.indexOf('\t')+1);
+
+	String [] fields = record.split("\t");
+	String hash = fields[0];
+	String title = fields[1];
+
+	Element d = this.doc.createElement("document");
+	d.setAttribute("hash", hash);
+	d.appendChild(GSXML.createTextElement(this.doc, "title", title));
+	
+	return d;
+
+    }
+    protected boolean addThesaurusList(Element phind_data, String record,
+				       String word,
+				       String freq,
+				       long first, long last) {
+
+
+	Element thesaurus_list = this.doc.createElement("thesaurusList");
+	phind_data.appendChild(thesaurus_list);
+	thesaurus_list.setAttribute("length", freq);
+	thesaurus_list.setAttribute("start", Long.toString(first));
+	thesaurus_list.setAttribute("end", Long.toString(last));
+	
+	// get the list of type,dest,dest
+	String [] links = record.split(";");
+	int length = links.length;
+	long index = 0;
+	for (int i = 0; i < length; i++) { // go through the entries
+	    String link_info = links[(int)i];
+	    String [] items = link_info.split(",");
+	    // the first entry is teh type
+	    String type = items[0];
+	    for (int j = 1; j<items.length; j++, index++) {
+		if (index >= first && index < last) { // only output the ones we want
+		    long phrase = Long.parseLong(items[j]);
+		    Element t = getThesaurus(phrase);
+		    t.setAttribute("type", type);
+		    thesaurus_list.appendChild(t);
+		}
+	    }
+	}
+
+	return true;
+    }
+
+    protected Element getThesaurus(long phrase_num) {
+
+	// look up the phrase in the pdata thingy
+	String record = this.mgpp_src.getDocument(this.basepath+File.separatorChar+"pdata", "Document",
+					      phrase_num);
+
+	if (record ==null || record.equals("")) return null;
+
+	// ignore everything up to and including first colon 
+	record = record.substring(record.indexOf(':')+1);
+
+	String [] fields = record.split(":");
+	String phrase = fields[0];
+	String tf = fields[1];
+	//String ef = fields[2]; dont use this
+	String df = fields[3];
+
+	Element thesaurus = this.doc.createElement("thesaurus");
+	thesaurus.setAttribute("tf", tf);
+	thesaurus.setAttribute("df", df);
+	thesaurus.setAttribute("id", Long.toString(phrase_num));
+	thesaurus.appendChild(GSXML.createTextElement(this.doc, "phrase", phrase));
+	return thesaurus;
+
+    }
+
+    /** returns an array of two elements - the prefix and the suffix*/
+    protected String [] splitPhraseOnWord(String phrase, String word) {
+	
+	if (word.equals("")) {
+	    
+	    String [] res =  {phrase, ""};
+	    return res;
+	}
+	// use 2 so that we only split on the first occurrance. trailing empty strings should be included 
+	String [] result = phrase.split(word, 2);
+	return result;
+	
+    }
+
+    protected Element phindError(String message) {
+	Element e = this.doc.createElement("phindError");
+	Text t = this.doc.createTextNode(message);
+	e.appendChild(t);
+	return e;
+    }
+    
+}
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/ServiceRack.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/ServiceRack.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/ServiceRack.java	(revision 14125)
@@ -0,0 +1,414 @@
+/*
+ *    ServiceRack.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.service;
+
+// greenstone classes
+import org.greenstone.gsdl3.util.*;
+import org.greenstone.gsdl3.core.*;
+
+// xml classes
+import org.w3c.dom.Node; 
+import org.w3c.dom.NodeList; 
+import org.w3c.dom.Element; 
+import org.w3c.dom.Document; 
+import org.xml.sax.InputSource;
+import javax.xml.parsers.*;
+import org.apache.xpath.XPathAPI;
+
+// general java classes
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.File;
+import java.util.HashMap;
+import java.util.ResourceBundle;
+import java.util.Locale;
+import java.lang.reflect.Method;
+
+import org.apache.log4j.*;
+
+/**
+ * ServiceRack - abstract base class for services
+ *
+ * A ServiceRack provides one or more Services. 
+ * This base class implements the process method.
+ *Each service is invoked
+ * by a method called process<service name> which takes one parameter - the xml request Element, and returns an XML response Element. 
+ * for example, the TextQuery service would be invoked by 
+ * processTextQuery(Element request)
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @version $Revision$
+ */
+public abstract class ServiceRack
+    implements ModuleInterface
+{
+
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.ServiceRack.class.getName());
+
+    /** the absolute address of the site home */
+    protected String site_home =null;
+    /** the http address of the site home */
+    protected String site_http_address =null;
+
+    /** the name of the cluster (or collection) that this service 
+	belongs to - if any */ 
+    protected String cluster_name = null;
+
+    /** some services can talk back to the message router */
+    protected MessageRouter router = null;
+
+    /** a converter class to create Documents etc */
+    protected XMLConverter converter = null;
+
+    /** the original config info - if need to store it */
+    protected Element config_info = null;
+
+    /** XML element for describe requests - the container doc */
+    protected Document doc = null;
+
+    /** XML element for describe requests - list of supported services
+	- this is static     */
+    protected Element short_service_info = null;
+
+    /** XML element for stylesheet requests - map of service name to format 
+	elem */
+    protected HashMap format_info_map = null;
+
+    /** A class loader that knows about the collection resources directory 
+     *  can put properties files, dtds etc  in here */
+    CollectionClassLoader class_loader = null;
+    
+    /** sets the cluster name */
+    public void setClusterName(String cluster_name) {
+	this.cluster_name = cluster_name;
+    }
+    /** sets the collect name */
+    public void setCollectionName(String coll_name) {
+	setClusterName(coll_name);
+    }
+
+    public void cleanUp() {}
+    
+    /** sets the site home */
+    public void setSiteHome(String site_home) {
+	this.site_home = site_home;
+    }
+    /** sets the site http address */
+    public void setSiteAddress(String site_address) {
+	this.site_http_address = site_address;
+    }
+
+    /** sets the message router */
+    public void setMessageRouter(MessageRouter m) {
+       this.router = m;
+    }
+
+    /** the no-args constructor */
+    public ServiceRack() {
+	this.converter = new XMLConverter();
+	this.doc = this.converter.newDOM();
+	this.short_service_info = this.doc.createElement(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER);
+	this.format_info_map = new HashMap();
+    }
+    
+
+    /** configure the service module
+     *
+     * @param info the XML node <serviceRack name="XXX"/> with name equal
+     * to the class name (of the subclass)
+     *
+     * must configure short_service_info_ and service_info_map_
+     * @return true if configured ok
+     * must be implemented in subclasses
+     */
+    public boolean configure(Element info) {
+	return configure(info, null);
+    }
+    
+    public boolean configure(Element info, Element extra_info) {
+	// set up the class loader
+	this.class_loader = new CollectionClassLoader(this.getClass().getClassLoader(), this.site_home, this.cluster_name);
+	return true;
+    }
+
+    /**
+     * Process an XML document - convenience method that uses Strings rather than Elements. just calls process(Element).
+     *
+     * @param xml_in the Document to process - a string
+     * @return the resultant document as a string - contains any error messages
+     * @see String
+     */
+    public String process(String xml_in) {
+	
+	Document doc = this.converter.getDOM(xml_in);
+	if (doc == null) {
+	    logger.error("Couldn't parse request");
+	    logger.error(xml_in);
+	    return null;
+	}
+	Element res = process(doc.getDocumentElement());
+	return this.converter.getString(res);
+	
+    }
+
+    /** process an XML request in DOM form
+     *
+     * @param xml_in the Element node containing the request
+     * should be <message> 
+     * @return an Element with the result XML
+     * @see Element
+     */
+    public Element process(Element message) {
+
+	NodeList requests = message.getElementsByTagName(GSXML.REQUEST_ELEM);
+	Document mess_doc = message.getOwnerDocument();
+	Element mainResult = this.doc.createElement(GSXML.MESSAGE_ELEM);
+	if (requests.getLength()==0) {
+	    // no requests
+	    return mainResult; // empty message for now
+	}
+
+	for (int i=0; i<requests.getLength(); i++) {
+	    Element request = (Element)requests.item(i);
+	
+	    String type = request.getAttribute(GSXML.TYPE_ATT);
+	    if (type.equals(GSXML.REQUEST_TYPE_DESCRIBE)) {
+		Element response = processDescribe(request);
+		if (response !=null) {
+		    mainResult.appendChild(this.doc.importNode(response, true));
+		}
+		
+	    } else if (type.equals(GSXML.REQUEST_TYPE_FORMAT)) {
+		Element response = processFormat(request);
+		    mainResult.appendChild(this.doc.importNode(response, true));
+		
+	       
+	    } else {
+		// other type of request, must be processed by the subclass - 
+		// send to the service method
+		StringBuffer error_string = new StringBuffer();
+		String to = GSPath.getFirstLink(request.getAttribute(GSXML.TO_ATT));		
+		Element response = null;
+		try {
+		    Class c = this.getClass();
+		    Class []params = {Class.forName("org.w3c.dom.Element")};
+		    
+		    String method_name = "process"+to;
+		    Method m = null;
+		    while (c != null) {
+			
+			try {
+			    m = c.getDeclaredMethod(method_name, params);
+			    // if this has worked, break
+			    break;
+			} catch (NoSuchMethodException e) {
+			    c = c.getSuperclass();
+			} catch (SecurityException e) {
+			    logger.error("security exception for finding method "+method_name);
+			    error_string.append("ServiceRack.process: security exception for finding method "+method_name);
+			}
+		    } // while
+		    if (m != null) {
+			Object []args = {request};
+			try {
+			    response = (Element)m.invoke(this, args);
+			    
+			} catch (Exception e) {
+			    logger.error("Trying to call a processService type method (process"+to+") on a subclass("+this.getClass().getName()+"), but an exception happened:"+e.toString());
+			    error_string.append("Trying to call a processService type method (process"+to+") on a subclass("+this.getClass().getName()+"), but an exception happened:"+e.toString());
+			}
+		    } else {
+			logger.error("method "+method_name+" not found for class "+this.getClass().getName());
+			error_string.append("ServiceRack.process: method "+method_name+" not found for class "+this.getClass().getName());
+		    }
+		    
+		} catch (ClassNotFoundException e) {
+		    logger.error("Element class not found");
+		    error_string.append("Element class not found");
+		}
+		if (response !=null) {
+		    mainResult.appendChild(this.doc.importNode(response, true));
+		} else {
+		    // add in a dummy response
+		    logger.error("adding in an error element\n");
+		    response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+		    GSXML.addError(this.doc, response, error_string.toString());
+		    mainResult.appendChild(response);
+		    
+		}
+ 
+	    } // else process request
+	} // for each request
+	
+	return mainResult;
+		
+    }
+
+ 
+
+    /** process method for describe requests 
+     */
+    protected Element processDescribe(Element request) {
+	
+	Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	response.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_DESCRIBE);
+	
+	String lang = request.getAttribute(GSXML.LANG_ATT);
+	String to = GSPath.getFirstLink(request.getAttribute(GSXML.TO_ATT));
+	if (to.equals("")) { // return the service list
+	    response.appendChild(getServiceList(lang));
+	    return response;
+	} 
+	response.setAttribute(GSXML.FROM_ATT, to);
+	Element param_list = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	Element description = null;
+	if (param_list == null) {
+	    description = getServiceDescription(to, lang, null);
+	} else {
+	    NodeList params = param_list.getElementsByTagName(GSXML.PARAM_ELEM);
+	    for (int i=0; i<params.getLength(); i++) {
+		
+		Element param = (Element)params.item(i);
+		// Identify the structure information desired
+		if (param.getAttribute(GSXML.NAME_ATT).equals(GSXML.SUBSET_PARAM )) {
+		    String info = param.getAttribute(GSXML.VALUE_ATT);
+		    if (description == null) {
+			 description = getServiceDescription(to, lang, info);
+		    } else {
+			Element temp = getServiceDescription(to, lang, info);
+			GSXML.mergeElements(description, temp);
+		    }
+		}
+	    }
+	}
+	if (description != null) { // may be null if non-existant service
+	    response.appendChild(description);
+	}
+	return response;
+    
+    }
+
+    /** process method for stylesheet requests
+     */
+    protected Element processFormat(Element request) {
+	Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	response.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_FORMAT);
+	
+	String to = GSPath.getFirstLink(request.getAttribute(GSXML.TO_ATT));
+	
+	if (to.equals("")) { // serviceRack query - is this appropriate??
+	    return response;
+	} 
+	
+	
+	// describe a particular service	
+	if (this.format_info_map.containsKey(to)) {
+	    response.appendChild(getServiceFormat(to));
+	    response.setAttribute(GSXML.FROM_ATT, to);
+	    return response;
+	}
+	// else no format info
+	logger.error("ServiceRack describe request: no format info for "+to+".");
+	return response;
+    }	
+    
+    /** returns the service list for the subclass */
+    protected Element getServiceList(String lang) {
+	// for now, it is static and has no language stuff
+	return (Element) this.short_service_info.cloneNode(true);
+    }
+    
+    /** returns a specific service description */
+    abstract protected Element getServiceDescription(String service, String lang, String subset);
+
+    protected Element getServiceFormat(String service) {
+	Element format = (Element)((Element)this.format_info_map.get(service)).cloneNode(true);
+	return format;
+    }
+
+    /** overloaded version for no args case */
+    protected String getTextString(String key, String lang) {
+	return getTextString(key, lang, null, null);
+    }
+
+    protected String getTextString(String key, String lang, String dictionary) {
+	return getTextString(key, lang, dictionary, null);
+    }
+    protected String getTextString(String key, String lang, String [] args) {
+	return getTextString(key, lang, null, args);
+    }
+	
+    /** getTextString - retrieves a language specific text string for the given
+key and locale, from the specified resource_bundle (dictionary)
+    */
+    protected String getTextString(String key, String lang, String dictionary, String[] args) {
+
+	// we want to use the collection class loader in case there are coll specific files
+	if (dictionary != null) {
+	    // just try the one specified dictionary
+	    Dictionary dict = new Dictionary(dictionary, lang, this.class_loader);
+	    String result = dict.get(key, args);
+	    if (result == null) { // not found
+		return "_"+key+"_";
+	    }
+	    return result;
+	}
+
+	// now we try class names for dictionary names
+	String class_name = this.getClass().getName();
+	class_name = class_name.substring(class_name.lastIndexOf('.')+1);
+	Dictionary dict = new Dictionary(class_name, lang, this.class_loader);
+	String result = dict.get(key, args);
+	if (result != null) {
+	    return result;
+	}
+
+	// we have to try super classes
+	Class c = this.getClass().getSuperclass();
+	while (result == null && c != null) {
+	    class_name = c.getName();
+	    class_name = class_name.substring(class_name.lastIndexOf('.')+1);
+	    if (class_name.equals("ServiceRack")) {
+		// this is as far as we go
+		break;
+	    }
+	    dict = new Dictionary(class_name, lang, this.class_loader);
+	    result = dict.get(key, args);
+	    c = c.getSuperclass();
+	}
+	if (result == null) {
+	    return "_"+key+"_";
+	}
+	return result;
+	
+    }
+
+    protected String getMetadataNameText(String key, String lang) {
+
+	String properties_name = "metadata_names";
+	Dictionary dict = new Dictionary(properties_name, lang);
+	
+	String result = dict.get(key);
+	if (result == null) { // not found
+	    return null;
+	} 
+	return result;
+    }
+}
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/TEIRetrieve.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/TEIRetrieve.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/TEIRetrieve.java	(revision 14125)
@@ -0,0 +1,52 @@
+package org.greenstone.gsdl3.service;
+
+
+// Greenstone classes
+import org.greenstone.gsdl3.util.*;
+
+// XML classes
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+// General Java classes
+
+// just needs to override a few methods that are TEI specific
+public class TEIRetrieve extends XMLRetrieve {
+
+   protected Element extractTitleMeta(Element section) {
+	
+	Element meta_elem = this.doc.createElement(GSXML.METADATA_ELEM);
+	meta_elem.setAttribute(GSXML.NAME_ATT, "Title");
+	
+	Element section_head = (Element)GSXML.getChildByTagName(section, "head");
+	if (section_head == null || !section_head.hasChildNodes()) {
+	    // there is no head element, so take the type attribute and make that the title
+	    String title = "("+section.getAttribute("type")+")";
+	    Text t = this.doc.createTextNode(title);
+	    meta_elem.appendChild(t);
+	} else {
+	    // add the head element as the metadata content
+	    meta_elem.appendChild(this.doc.importNode(section_head, true));
+	}
+	return meta_elem;
+    }
+
+    // this assumes that the scope refers to a top level node - this may be overwritten if the scope bit in the id is a shorthand of some sort
+    protected String translateScope(String scope) {
+	if (scope.equals("front")) {
+	    return "text/front";
+	}
+	if (scope.equals("body")) {
+	    return "text/body";
+	}
+	if (scope.equals("back")) {
+	    return "text/back";
+	}
+	if (scope.equals("full")) { // is this ever used???
+	    return "";
+	}
+	return scope;
+    }
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/XMLRetrieve.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/XMLRetrieve.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/XMLRetrieve.java	(revision 14125)
@@ -0,0 +1,448 @@
+package org.greenstone.gsdl3.service;
+
+
+// Greenstone classes
+import org.greenstone.gsdl3.util.*;
+
+// XML classes
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Text;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.NamedNodeMap;
+
+// General Java classes
+import java.io.File;
+import java.util.Vector;
+import java.util.HashMap;
+
+import org.apache.log4j.*;
+
+public class XMLRetrieve extends ServiceRack {
+
+      static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.XMLRetrieve.class.getName());
+    protected static final String CONTENT_SERVICE = "DocumentContentRetrieve";
+    protected static final String METADATA_SERVICE = "DocumentMetadataRetrieve";
+    protected static final String STRUCTURE_SERVICE = "DocumentStructureRetrieve";
+    
+    protected String toc_xsl_name = "";
+    protected String document_encoding = "";
+    protected String document_root_tag = "";
+    
+    protected Element collection_doc_list = null;
+    
+    protected boolean provide_content = true;
+    protected boolean provide_structure = true;
+    protected boolean provide_metadata = true;
+    
+
+    public boolean configure(Element info, Element extra_info) {
+	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+	logger.info("configuring XMLRetrieve...");
+	// look for the parameters
+	Element param_list = (Element)GSXML.getChildByTagName(info, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	HashMap params;
+	String services_to_provide = "";
+	if (param_list != null) {
+	    params = GSXML.extractParams(param_list, false);
+	    this.toc_xsl_name = (String)params.get("tocXSLT");
+	    this.document_encoding = (String)params.get("documentEncoding");
+	    this.document_root_tag = (String)params.get("documentRootTag");
+	    services_to_provide = (String)params.get("provideServices");
+	}
+	if (this.toc_xsl_name == null || this.toc_xsl_name.equals("")) {
+	    this.toc_xsl_name = "default_toc";
+	}
+	this.toc_xsl_name  = this.toc_xsl_name+".xsl";
+	
+	if (this.document_encoding == null || this.document_encoding.equals("")) {
+	    this.document_encoding = "UTF-8";
+	}
+	
+	if (services_to_provide != null && !services_to_provide.equals("")) {
+	    if (services_to_provide.indexOf("content")==-1) {
+		provide_content = false;
+	    }
+	    if (services_to_provide.indexOf("metadata")==-1) {
+		provide_metadata = false;
+	    }
+	    if (services_to_provide.indexOf("structure")==-1) {
+		provide_structure = false;
+	    }
+	    
+	}
+	
+	// set up short_service_info_ - for now just has name and type
+	Element retrieve_service;
+	if (provide_content) {
+	    retrieve_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    retrieve_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
+	    retrieve_service.setAttribute(GSXML.NAME_ATT, CONTENT_SERVICE);
+	    this.short_service_info.appendChild(retrieve_service);
+	}
+	if (provide_metadata) {
+	    retrieve_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    retrieve_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
+	    retrieve_service.setAttribute(GSXML.NAME_ATT, METADATA_SERVICE);
+	    this.short_service_info.appendChild(retrieve_service);
+	}
+	if (provide_structure) {
+	    retrieve_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	    retrieve_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
+	    retrieve_service.setAttribute(GSXML.NAME_ATT, STRUCTURE_SERVICE);
+	    this.short_service_info.appendChild(retrieve_service);
+	}
+	// find the doc list from the extra_info and keep it - should this be in collect.cfg or build.cfg??
+	collection_doc_list = (Element)GSXML.getChildByTagName(extra_info, GSXML.DOCUMENT_ELEM+GSXML.LIST_MODIFIER);
+
+	GSEntityResolver resolver = new GSEntityResolver();
+	resolver.setClassLoader(this.class_loader);
+	this.converter.setEntityResolver(resolver);
+	return true;
+    }
+
+    // this may get called but is not useful in the case of retrieve services
+    protected Element getServiceDescription(String service_id, String lang, String subset) {
+
+	Element retrieve_service = this.doc.createElement(GSXML.SERVICE_ELEM);
+	retrieve_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
+	retrieve_service.setAttribute(GSXML.NAME_ATT, service_id);
+	return retrieve_service;
+    }
+    
+    protected Element processDocumentContentRetrieve(Element request) {
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.setAttribute(GSXML.FROM_ATT, CONTENT_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+	
+	Element doc_list = (Element)GSXML.getChildByTagName(request, GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	if (doc_list == null) {
+	    return result;
+	}
+	Element result_doc_list = (Element)this.doc.importNode(doc_list, true);
+	result.appendChild(result_doc_list);
+
+	NodeList docs = result_doc_list.getElementsByTagName(GSXML.DOC_NODE_ELEM);
+	for (int i=0; i<docs.getLength(); i++) {
+
+	    Element doc = (Element)docs.item(i);
+	    Element content = this.doc.createElement(GSXML.NODE_CONTENT_ELEM);
+	    doc.appendChild(content);
+
+	    String node_id = doc.getAttribute(GSXML.NODE_ID_ATT);
+	    String doc_name = getWorkName(node_id);
+	    
+	    Element doc_elem = loadDocument(doc_name); // should perhaps cache the read in docs??
+	    if (doc_elem == null) {
+		continue;
+	    } 
+
+	    
+	    // if we have asked for the whole doc, just append it
+	    if (doc_name.equals(node_id)) {
+		content.appendChild(this.doc.importNode(doc_elem, true));
+		continue;
+	    }
+		   
+	    // else we only want a sub section
+	    
+	    Element section = getSection(doc_elem, node_id);
+	    if (section != null) {
+		content.appendChild(this.doc.importNode(section, true));
+	    }
+	    
+	} // for each doc
+
+	return result;
+	
+    }
+    
+    protected Element processDocumentStructureRetrieve(Element request) {
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.setAttribute(GSXML.FROM_ATT, STRUCTURE_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+	
+	Element doc_list = (Element)GSXML.getChildByTagName(request, GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	if (doc_list == null) {
+	    logger.error("no documents specified in the request. ");
+	    return result;
+	}
+
+	Element result_doc_list = (Element)this.doc.importNode(doc_list, true);
+	result.appendChild(result_doc_list);
+	// first look for the stylesheet in the collection
+	File stylesheet = new File(GSFile.collStylesheetFile(this.site_home, this.cluster_name, this.toc_xsl_name));
+	if (!stylesheet.exists()) {
+	    // now try in the site
+	    stylesheet = new File(GSFile.siteStylesheetFile(this.site_home, this.toc_xsl_name));
+	}
+	if (!stylesheet.exists()) {
+	    logger.error("couldn't find the stylesheet file to produce the table of contents:"+stylesheet.getPath());
+	    return result;
+	}
+
+	// for now, we dont have any params, and we always return the structure of the whole document
+	
+	XMLTransformer transformer = new XMLTransformer();
+	NodeList docs = result_doc_list.getElementsByTagName(GSXML.DOC_NODE_ELEM);
+
+	for (int i=0; i<docs.getLength(); i++) {
+
+	    Element doc = (Element)docs.item(i);
+	    
+	    Element structure = this.doc.createElement(GSXML.NODE_STRUCTURE_ELEM);
+	    doc.appendChild(structure);
+	    String doc_name = doc.getAttribute(GSXML.NODE_ID_ATT);
+	    // make sure we are at the top level
+	    doc_name = getWorkName(doc_name);
+	    
+	    File doc_file = new File(GSFile.collectionIndexDir(this.site_home, this.cluster_name)+File.separator+"text"+File.separatorChar+doc_name+".xml");
+	    
+	    if (!doc_file.exists()) {
+		logger.error("couldn't find file in coll "+this.cluster_name +", file "+doc_name+".xml");
+	    } else {
+		try {
+		    Node toc = transformer.transform(stylesheet, doc_file);
+		    structure.appendChild(this.doc.importNode(toc, true));
+		} catch (Exception e) {
+		    logger.error("couldn't transform the document to get the toc");
+		}
+	    }
+	    
+	}
+	
+	return result;
+	
+    }
+    
+    // this just extracts a bit of text from the section to use as the Title
+    // this should be overwritten for any format that  has something more suitable
+    protected Element processDocumentMetadataRetrieve(Element request) {
+	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
+	result.setAttribute(GSXML.FROM_ATT, METADATA_SERVICE);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+	
+	Element doc_list = (Element)GSXML.getChildByTagName(request, GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
+	if (doc_list == null) {
+	    logger.error("no documents in the request");
+	    return result;
+	}
+
+	Element result_doc_list = (Element)this.doc.importNode(doc_list, true);
+	result.appendChild(result_doc_list);
+
+	Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	if (param_list == null) {
+	    logger.error("no metadata in the request");
+	    return result;
+	}
+	
+	Vector meta_name_list = new Vector();
+	boolean all_metadata = false;
+	// Process the request parameters
+	Element param = (Element) param_list.getFirstChild();
+	while (param != null) {
+	    // Identify the metadata information desired
+	    if (param.getAttribute(GSXML.NAME_ATT).equals("metadata")) {
+		String metadata = GSXML.getValue(param);
+		if (metadata.equals("all")) {
+		    all_metadata = true;
+		    break;
+		}
+		meta_name_list.add(metadata);
+	    }
+	    param = (Element) param.getNextSibling();
+	}
+		
+	NodeList docs = result_doc_list.getElementsByTagName(GSXML.DOC_NODE_ELEM);
+	for (int i=0; i<docs.getLength(); i++) {
+	    Element doc = (Element)docs.item(i);
+	    String node_id = doc.getAttribute(GSXML.NODE_ID_ATT);
+	    String doc_name = getWorkName(node_id);
+	    
+	    Element metadata_list = getMetadata(node_id, all_metadata, meta_name_list); 
+	    doc.appendChild(metadata_list);
+	}
+	
+	return result;
+    }
+    
+    protected Element loadDocument(String doc_name) {
+	// try to find the document
+	File doc_file = new File(GSFile.collectionIndexDir(this.site_home, this.cluster_name)+File.separator+"text"+File.separatorChar+doc_name+".xml");
+	    
+	if (!doc_file.exists()) {
+	    logger.info("couldn't find file in coll "+this.cluster_name +", file "+doc_name+".xml");
+	    return null;
+	}
+	
+	Document the_doc = null;
+	try {
+	    the_doc = this.converter.getDOM(doc_file, this.document_encoding);
+	} catch (Exception e) {
+	    logger.error("couldn't create a DOM from file "+doc_file.getPath());
+	    return null;
+	}
+	
+	return the_doc.getDocumentElement();
+
+    }
+
+    
+    protected Element getSection(Element doc_elem, String node_id) {
+	String [] bits = node_id.split("\\.");
+	if (bits.length > 4) {
+	    logger.error("badly formatted node id ("+node_id +"), cant retrieve the section");
+	    return null;
+	}
+	    
+	String id="";
+	String tagname = "";
+	String scope = "";
+	if (bits.length==2) {
+	    tagname = bits[1];
+	} else { 
+	    scope = bits[1];
+	    tagname = bits[2];
+	    
+	    if (bits.length == 4) {
+		id = bits[3];
+	    }
+	}
+	scope = translateScope(scope);
+	Element top=null;
+	if (!scope.equals("")) {
+	    top = (Element)GSXML.getNodeByPath(doc_elem, scope);
+	    if (top == null) {
+		// something gone wrong
+		return null;
+	    }
+	} else {
+	    top = doc_elem;
+	}
+	
+	NodeList elements = top.getElementsByTagName(tagname);
+	if (elements.getLength() == 0) {
+	    return null;
+	}
+	// no id, just return the first one
+	if (id.equals("")) {
+	    return (Element)elements.item(0);
+	}
+	// have an id, need to check and find the right one.
+	for (int i=0; i<elements.getLength();i++) {
+	    Element e = (Element)elements.item(i);
+	    if (e.getAttribute("gs3:id").equals(id)) {
+		return e;
+	    }
+	}
+	return null;
+	
+    }
+
+    protected Element getMetadata(String node_id, boolean all, Vector meta_name_list) {
+
+	// our default strategy here is to only return Title and root:Title
+	// ignore all others 
+	// the title of a section is just a little bit of the text inside it.
+	// the root_Title is the title from the doc info in the config file
+	Element metadata_list = this.doc.createElement(GSXML.METADATA_ELEM+ GSXML.LIST_MODIFIER);
+	String doc_name = getWorkName(node_id);
+	boolean node_is_root = false;
+	if (doc_name.equals(node_id)) {
+	    node_is_root = true;
+	}
+	
+	Element this_doc = GSXML.getNamedElement(this.collection_doc_list, GSXML.DOCUMENT_ELEM, GSXML.NAME_ATT, doc_name);
+	Element doc_meta_list  = (Element) GSXML.getChildByTagName(this_doc, GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
+	
+	boolean get_section_title = false;
+	
+	if (all) {
+	    if (node_is_root) {
+	    return (Element)this.doc.importNode(doc_meta_list, true);
+	    } else {
+		get_section_title = true;
+	    }
+	    
+	} else {
+	    // have to process metadata one by one
+	    for (int i=0; i<meta_name_list.size(); i++) {
+		String meta_name = (String) meta_name_list.elementAt(i);
+		String actual_meta_name = meta_name;
+		if (meta_name.startsWith("root_")) {
+		    actual_meta_name = meta_name.substring(5);
+		} else {
+		    // its a section level one - check to see if doc is root
+		    if (!node_is_root) {
+			if (meta_name.equals("Title")) {
+			    get_section_title = true;
+			}
+			continue; // move on to teh next metadata
+		    }
+		}
+		
+		// here, we look for the specific meta elem in doc_meta_list
+		Element meta_item = GSXML.getNamedElement(doc_meta_list, GSXML.METADATA_ELEM, GSXML.NAME_ATT, actual_meta_name);
+		if (meta_item != null) {
+		    meta_item = (Element)this.doc.importNode(meta_item, true);
+		    meta_item.setAttribute(GSXML.NAME_ATT, meta_name);
+		    metadata_list.appendChild(meta_item);
+		}
+	    } // for each metadata
+	}
+
+	// now we have processed all teh doc metadata, just have section one to go, if needed
+	if (get_section_title) {
+	    
+	    Element doc_elem = loadDocument(doc_name);
+	    if (doc_elem != null) {
+		Element section = getSection(doc_elem, node_id);
+		if (section != null) {
+		    Element title_meta = extractTitleMeta(section);
+		    if (title_meta != null) {
+			metadata_list.appendChild(title_meta);
+		    }
+		}
+	    }
+		
+	}
+	return metadata_list;
+    }
+    
+    protected Element extractTitleMeta(Element section) {
+	Element meta_elem = this.doc.createElement(GSXML.METADATA_ELEM);
+	meta_elem.setAttribute(GSXML.NAME_ATT, "Title");
+
+	String title = "dummy title";
+	Text t = this.doc.createTextNode(title);
+	meta_elem.appendChild(t);
+	return meta_elem;
+
+    }
+    // some methods for handling nodeIDs - they may be different for different colls, so they can be overwritten
+
+    // the full default nodeID looks like work.scope.tag.id
+    // the shorter versions are work, work.tag, work.scope.tag
+    protected String getWorkName(String node_id) {
+	int pos = node_id.indexOf('.');
+	if (pos == -1) {
+	    return node_id;
+	}
+	return node_id.substring(0, pos);
+    }
+    
+    // this assumes that the scope refers to a top level node - this may be overwritten if the scope bit in the id is a shorthand of some sort
+    protected String translateScope(String scope) {
+	if (this.document_root_tag != null) {
+	    return GSPath.appendLink(this.document_root_tag, scope);
+	}
+	return scope;
+    }
+    
+}
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/XSLTServices.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/XSLTServices.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/service/XSLTServices.java	(revision 14125)
@@ -0,0 +1,268 @@
+/*
+ *    XSLTServices.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.service;
+
+import org.greenstone.gsdl3.util.*;
+import org.greenstone.gsdl3.selfContained.*;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import org.apache.xerces.dom.DocumentImpl;
+import org.apache.xerces.dom.ElementImpl;
+import org.apache.xerces.dom.TextImpl;
+import org.w3c.dom.Document; 
+import org.w3c.dom.Node; 
+import org.w3c.dom.Text; 
+import org.w3c.dom.Element; 
+import org.w3c.dom.NodeList; 
+
+import java.util.HashMap;
+import java.util.Vector;
+import java.util.Set;
+import java.util.Map;
+import java.util.Iterator;
+import java.util.Locale;
+import java.io.*;
+import java.net.URLEncoder;
+import java.net.URLDecoder;
+
+import org.apache.log4j.*;
+
+/**
+ * A ServiceRack class for XSLT query. 
+ *
+ * Document ids are formed by encoding the document using standard URLEncoding
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @author <a href="mailto:s.yeates@cs.waikato.ac.nz">Stuart Yeates</a>
+ * @version $Revision$
+ * @see ServiceRack
+ * @see java.net.URLEncoder
+ * @see java.net.URLDecoder
+ */
+
+public class XSLTServices 
+  extends ServiceRack {
+  
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.XSLTServices.class.getName());
+
+  // these strings must match what is found in the properties file
+  // the services on offer
+  private static final String XSLT_QUERY_SERVICE        = "XSLTQuery";
+  private static final String RESOURCE_RETRIEVE_SERVICE = "ResourceRetrieve";
+  // params used
+  private static final String QUERY_PARAM        = "query";
+  private static final String ALPHABET_PARAM     = "alphabet";
+  
+  private static final int RESULT_SET_SIZE        = 10;
+
+  // alphabets
+  private static final String MINIMUM_ALPHABET   = "minimum";
+  private static final String ASCII_ALPHABET     = "ascii";
+  private static final String UNICODE_ALPHABET   = "unicode";
+
+  private static final String DEFAULT_QUERY_STRING   =
+    "<xsl:stylesheet version=\"1.0\""+
+    "                xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">"+
+    "    <xsl:template match=\"*|/\">"+
+    "         <xsl:apply-templates/>"+
+    "    </xsl:template>"+
+    "    <xsl:template match=\"*|/\" mode=\"m\">"+
+    "         <xsl:apply-templates mode=\"m\"/>"+
+    "    </xsl:template>"+
+    "    <xsl:template match=\"text()|@*\">"+
+    "         <xsl:value-of select=\".\"/>"+
+    "    </xsl:template>"+
+    "    <xsl:template match=\"processing-instruction()|comment()\"/>"+
+    "</xsl:stylesheet>";
+  
+
+  private String alphabet = MINIMUM_ALPHABET;
+  private Element config_info_ = null;
+  
+
+  public XSLTServices() {
+  }
+  
+    /** configure this service */
+    public boolean configure(Element info, Element extra_info) {
+      	if (!super.configure(info, extra_info)){
+	    return false;
+	}
+
+      logger.info("configuring XSLTServices");
+      this.config_info = info;
+    try {
+      logger.info("called with:");
+      TransformerFactory transformerFactory = TransformerFactory.newInstance();
+      Element doc = (Element)info.getFirstChild();
+      Transformer transformer = transformerFactory.newTransformer();
+      StreamResult result = new StreamResult(System.out);
+      Source source = new DOMSource(doc);
+      transformer.transform(source,result);
+    } catch (Throwable t) {
+      logger.error("Error printing XML in XSLTService::configure()");
+    }
+    return true;    
+  }
+
+    protected Element getServiceDescription(String service, String lang, String subset) {
+
+	return null;
+    }
+  
+  /** process method for specific services - must be implemented by all
+   * subclasses
+   * should implement all services supported by the servicesImpl except
+   * for describe, which is implemented by this base class
+   *
+   */
+  protected Element processService(String service, Element request){
+    if (service.equals(XSLT_QUERY_SERVICE)) {
+      return processXSLTQuery(request);
+    } else if (service.equals(RESOURCE_RETRIEVE_SERVICE)) {
+      return processResourceRetrieve(request);
+    }
+    // create the response so we can report the error
+    Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+    String from = GSPath.appendLink(this.cluster_name, RESOURCE_RETRIEVE_SERVICE);
+    response.setAttribute(GSXML.FROM_ATT, from);
+    response.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+    
+    logger.error("should never get here. service type wrong:"+service);
+    GSXML.addError(this.doc, response,"XSLTServices:should never get here. service type wrong:"+service);
+    return response;
+  }
+
+  /** process a document resquest query */
+  protected Element processResourceRetrieve(Element request) {
+    
+    // create the result and set the path so we know where we are
+    Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+    String from = GSPath.appendLink(this.cluster_name, RESOURCE_RETRIEVE_SERVICE);
+    response.setAttribute(GSXML.FROM_ATT, from);
+    response.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+
+    // get param list 
+    Element param_elem=null;
+    Node n = request.getFirstChild();
+    while (n!=null) {
+	String node_name = n.getNodeName();
+	if (node_name.equals(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER)) {
+	    param_elem = (Element)n;
+	    break;
+	}
+	n = n.getNextSibling();
+    }
+
+    if (param_elem==null) { 
+	logger.error("bad query request");
+	GSXML.addError(this.doc, response,"bad query request in XSLTServices");
+	return response; 
+    }
+    
+    // Documents are just the ids decoding using standard URL decoding
+    
+    Element doc_list = (Element)GSXML.getChildByTagName(request, GSXML.DOCUMENT_ELEM+GSXML.LIST_MODIFIER);
+    String []ids = GSXML.getAttributeValuesFromList(doc_list, GSXML.NAME_ATT);
+    for (int j=0; j<ids.length; j++) {
+      String document = null;
+      try {
+	document = URLDecoder.decode(ids[j],"UTF-8");
+      } catch (UnsupportedEncodingException e) {
+	throw new Error(e.toString());
+      }
+      // something funny with the doc - 
+      Element new_doc = this.doc.createElement(GSXML.DOCUMENT_ELEM);
+      new_doc.setAttribute(GSXML.NAME_ATT, ids[j]); //GSXML.createDocumentElement(this.doc, ids[j]);
+      GSXML.addDocText(this.doc, new_doc, document);
+      response.appendChild(new_doc);
+    }
+    
+    return response;
+  }
+  
+  /** process a XSLT query */
+  protected Element processXSLTQuery(Element request) {
+    
+    // create the result and set the path so we know where we are
+    Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
+    String from = GSPath.appendLink(this.cluster_name, XSLT_QUERY_SERVICE);
+    response.setAttribute(GSXML.FROM_ATT, from);
+    response.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
+
+    // get the parameter list
+    Element param_list = 
+      (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+
+    // extract the only parameter we care about
+    HashMap params = GSXML.extractParams(param_list, false);
+    String query = (String)params.get(QUERY_PARAM);
+    
+    if (query == null || query.equals(""))
+      query = DEFAULT_QUERY_STRING;
+    
+    
+    DocumentStream stream = null;
+    if (alphabet.equals(MINIMUM_ALPHABET)){
+      stream = new GeneratedDocumentStream('a','c');
+    } else if(alphabet.equals(ASCII_ALPHABET)){
+      stream = new GeneratedDocumentStream();
+    } else if(alphabet.equals(UNICODE_ALPHABET)){
+      stream = new GeneratedDocumentStream(Character.MIN_VALUE,
+					   Character.MAX_VALUE);
+    } else {
+      logger.error("bad alphabet name : "+ alphabet);
+      GSXML.addError(this.doc, response,"XSLTServices: bad alphabet name : "+ alphabet);
+      stream = new GeneratedDocumentStream();
+    }
+
+    Element resource_list = this.doc.createElement(GSXML.RESOURCE_ELEM+GSXML.LIST_MODIFIER);
+    response.appendChild(resource_list);
+
+    // Framework to stringise the document
+    TransformerFactory transformerFactory = TransformerFactory.newInstance();
+
+    // add each resource
+    for (int d=0; d<RESULT_SET_SIZE; d++) {
+      try {
+	Document document = stream.nextDocument();
+	Element doc = (Element)document.getFirstChild();
+	Transformer transformer = transformerFactory.newTransformer();
+	StringWriter writer = new StringWriter();
+	StreamResult result = new StreamResult(writer);
+	Source source = new DOMSource(doc);
+	transformer.transform(source,result);
+	String id = writer.toString();
+	Element e = this.doc.createElement(GSXML.DOCUMENT_ELEM);
+	e.setAttribute(GSXML.NAME_ATT, id); 
+	//Node no = GSXML.createDocumentElement(this.doc, id);
+	resource_list.appendChild(e);
+      } catch (Throwable t) {
+	GSXML.addError(this.doc, response, "Error in XSLTServices finding results:" + t.toString());
+      }
+    }
+    return response; 
+  }
+}  
+ 
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/CollectionClassLoader.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/CollectionClassLoader.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/CollectionClassLoader.java	(revision 14125)
@@ -0,0 +1,45 @@
+/*
+ *    CollectionClassLoader.java
+ *    Copyright (C) 2005 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.util;
+
+import java.net.URL;
+import java.io.File;
+
+/** Looks for classes/resources in the collection resources directory 
+ */
+public class CollectionClassLoader
+    extends ClassLoader {
+
+    String base_dir = null;
+    public CollectionClassLoader(ClassLoader parent, String site_home, String collection_name) {
+	super(parent);
+	this.base_dir = GSFile.collectionResourceDir(site_home, collection_name);
+    } 
+
+    public URL findResource(String name) {
+	File resource_path = new File(this.base_dir, name);
+	try {
+	    if (resource_path.exists()) {
+		return new URL("file://"+resource_path.getAbsolutePath());
+	    }
+	} catch (Exception e) {};
+
+	return super.findResource(name);
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/DBInfo.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/DBInfo.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/DBInfo.java	(revision 14125)
@@ -0,0 +1,64 @@
+package org.greenstone.gsdl3.util;
+
+import java.util.Vector;
+import java.util.HashMap;
+import java.util.Set;
+/** class to hold info from a gdbm (or equiv) query
+ * maps a String key to a list of Strings (values)
+ * at the moment, the user must know if something has a single value or not
+ */
+public class DBInfo {
+
+    protected HashMap info_map_;
+
+    public DBInfo() {
+	info_map_ = new HashMap();
+    }
+
+    // methods for keys that can have a single value
+
+    /** set the value for a key - replaces any existing value */
+    public void setInfo(String key, String value) {
+	Vector v = new Vector();
+	v.add(value);
+	info_map_.put(key, v);
+    }
+
+    /** get the value - used for keys that have one value, otherwise just
+     * returns the first one */
+    public String getInfo(String key) {
+	Vector items = (Vector)info_map_.get(key);
+	if (items==null) {
+	    return "";
+	}
+	return (String)items.firstElement();
+    }
+
+    // methods for keys that can have multiple values
+    
+    /** add a value to a key - for keys that can have multiple values */
+    public void addInfo(String key, String value) {
+	Vector v = (Vector)info_map_.get(key);
+	if (v==null) {
+	    v = new Vector();
+	}
+	v.add(value);
+	info_map_.put(key, v);
+    }
+    /** return a vector of all values associated with a key 
+     * @return Vector of Strings
+     */
+    public Vector getMultiInfo(String key) {
+	return (Vector)info_map_.get(key);
+    }
+
+    /** returns a list of all the keys in the info */
+    public Set getKeys() {
+	return info_map_.keySet();
+    }
+    /** returns the Info as a string */
+    public String toString() {
+	return info_map_.toString();
+
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/Dictionary.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/Dictionary.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/Dictionary.java	(revision 14125)
@@ -0,0 +1,150 @@
+/*
+ *    Dictionary.java
+ *    Copyright (C) 2005 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.util;
+
+import java.util.ResourceBundle;
+import java.util.Locale;
+import java.util.Enumeration;
+
+import org.apache.log4j.*;
+
+public class Dictionary {
+
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.util.Dictionary.class.getName());
+
+    /** The locale of this dictionary. */
+    protected Locale locale = null;
+    
+    /** The resource that has been loaded */
+    protected String resource = null;
+
+    /** The ResourceBundle which contains the raw key-value mappings. Loaded from a file named "resource_locale.properties*/
+    private ResourceBundle raw = null;
+
+    /**  Constructs the Dictionary class by first creating a locale from the specified language, (or using the default locale if this didn't work), then loading a resource bundle based on this locale. 
+     */
+    public Dictionary(String resource, String lang) {
+	// Initialize.
+	
+	this.locale = new Locale(lang);
+	this.resource = resource;
+	if (this.locale == null) {
+	    this.locale = Locale.getDefault();
+	}
+	try {
+	    this.raw = ResourceBundle.getBundle(this.resource, this.locale);
+	} catch (Exception e) {
+	    //logger.debug("Dictionary: couldn't locate a resource bundle for "+resource);
+	}
+    }
+
+    public Dictionary(String resource, Locale locale) {
+	this.locale = locale;
+	this.resource = resource;
+	try {
+	    this.raw = ResourceBundle.getBundle(this.resource, this.locale);
+	} catch (Exception e) {
+	    //logger.debug("Dictionary: couldn't locate a resource bundle for "+resource);
+	}
+    }
+
+    /**  Constructs the Dictionary class by first creating a locale from the specified language, (or using the default locale if this didn't work), then loading a resource bundle based on this locale. A classloader is specified which can be used to find the resource.
+     */
+    public Dictionary(String resource, String lang, ClassLoader loader) {
+	// Initialize.
+	
+	this.locale = new Locale(lang);
+	this.resource = resource;
+	if (this.locale == null) {
+	    this.locale = Locale.getDefault();
+	}
+	// try the specified class loader
+	try {
+	    this.raw = ResourceBundle.getBundle(this.resource, this.locale, loader);
+	    return;
+	} catch (Exception e) {};
+	
+	try {
+	    this.raw = ResourceBundle.getBundle(this.resource, this.locale);
+	} catch (Exception ex) {
+	    //logger.debug("Dictionary: couldn't locate a resource bundle for "+resource);
+	}
+	
+    }
+
+    
+    public Enumeration getKeys() {
+	if (this.raw != null) {
+	    return this.raw.getKeys();
+	}
+	return null;
+    }
+    /** Overloaded to call get with both a key and an empty argument array.
+     * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
+     * @return A <strong>String</strong> which has been referenced by the key String and that  contains no argument fields.
+     */
+    public String get(String key) {
+	return get(key, null);
+    }
+    
+    /** Used to retrieve a property value from the Locale specific ResourceBundle, based upon the key and arguments supplied. If the key cannot be found or if some other part of the call fails a default (English) error message is returned. <BR>
+     * Here the get recieves a second argument which is an array of Strings used to populate argument fields, denoted {<I>n</I>}, within the value String returned.
+     * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
+     * @param args A <strong>String[]</strong> used to populate argument fields within the complete String.
+     * @return A <strong>String</strong> which has been referenced by the key String and that either contains no argument fields, or has had the argument fields  populated  with argument Strings provided in the get call.
+     */
+    public String get(String key, String args[]) {
+	if (this.raw == null) {
+	    return null;
+	}
+	try {
+	    String initial_raw = this.raw.getString(key);
+	    // convert to unicode, copied from gatherer dictionary
+	    String initial = new String(initial_raw.getBytes("ISO-8859-1"), "UTF-8");
+	    // If the string contains arguments we have to insert them.
+	    String complete = "";
+	    // While we still have initial string left.
+	    while(initial.length() > 0 && initial.indexOf('{') != -1 && initial.indexOf('}') != -1) {
+		// Remove preamble
+		int opening = initial.indexOf('{');
+		int closing = initial.indexOf('}');
+		complete = complete + initial.substring(0, opening);
+		// Parse arg_num
+		String arg_str = initial.substring(opening + 1, closing);
+		int arg_num = Integer.parseInt(arg_str);
+		if(closing + 1 < initial.length()) {
+		    initial = initial.substring(closing + 1);
+		}
+		else {
+		    initial = "";
+		}
+		// Insert argument
+		if(args != null && 0 <= arg_num && arg_num < args.length) {
+		    complete = complete + args[arg_num];
+		}
+	    }
+	    return complete + initial;
+	}
+	catch (Exception e) {
+	    //logger.debug("Dictionary Error: couldn't find string for key:" + key +" in resource "+this.resource);
+	    return null;
+	}
+    }
+}
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GDBMWrapper.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GDBMWrapper.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GDBMWrapper.java	(revision 14125)
@@ -0,0 +1,295 @@
+package org.greenstone.gsdl3.util;
+
+import au.com.pharos.gdbm.GdbmFile;
+import au.com.pharos.packing.*;
+import au.com.pharos.gdbm.GdbmException;
+
+import org.apache.log4j.*;
+
+/** java wrapper class for gdbm - uses Java-GDBM written by Martin Pool
+ * replaces gdbmclass in the old version
+ */
+
+public class GDBMWrapper {
+
+      static Logger logger = Logger.getLogger(org.greenstone.gsdl3.util.GDBMWrapper.class.getName());
+
+
+    // Values must match those from gdbm.h - uses the definitions from GdbmFile !
+    /** Indicates that the caller will just read the database.  Many
+     * readers may share a database. */
+    public final static int READER = GdbmFile.READER;
+ 
+    /** The caller wants read/write access to an existing database and
+     * requires exclusive access. */
+    public final static int WRITER = GdbmFile.WRITER;
+ 
+    /** The caller wants exclusive read/write access, and the database
+     * should be created if it does not already exist. */
+    public final static int WRCREAT = GdbmFile.WRCREAT;
+ 
+    /** The caller wants exclusive read/write access, and the database
+     * should be replaced if it already exists. */
+    public final static int NEWDB = GdbmFile.NEWDB;
+
+    protected GdbmFile db_=null;
+
+    /** open the database filename, with mode mode - uses the constants
+	above, eg GdbmFile.WRITER */
+    public boolean openDatabase(String filename, int mode){
+	try {
+	    if (db_!=null) {
+		db_.close();
+	    }
+	    db_ = new GdbmFile(filename, mode);
+	} catch ( GdbmException e) { // the database wasn't opened or created
+	    logger.error("couldn't open database "+filename);
+	    return false;
+	} 
+	db_.setKeyPacking(new StringPacking());
+	db_.setValuePacking(new StringPacking());
+	return true;
+    }
+
+    /** cloase the database associated with this wrapper */
+    public void closeDatabase() {
+	try {
+	    if (db_ != null) {
+		db_.close();
+		db_ = null;
+	    }
+	} catch (GdbmException e) {
+	    // should never get here - close never actually throws an exception
+	    logger.error("error on close()");
+	}
+    }
+
+    /** returns a DBInfo object containing all the name-value pairs for 
+     * main_key 
+     * @see DBInfo
+     */
+    public DBInfo getInfo(String main_key) {
+	if (db_==null) {
+	    return null;
+	}
+	String s_info;
+	try {
+	    s_info = (String)db_.fetch(main_key);
+	} catch (GdbmException e) {
+	    logger.error("couldn't get record");
+	    return null;
+	}
+	if (s_info==null) {
+	    // record not present
+	    logger.error("key "+main_key+" not present in db");
+	    return null;
+	}
+	DBInfo info = new DBInfo();
+
+	String [] lines = s_info.split("\n");
+	String key;
+	String value;
+	for (int i=0; i<lines.length; i++) {
+	    logger.debug("line:"+lines[i]);
+	    int a = lines[i].indexOf('<');
+	    int b= lines[i].indexOf('>');
+	    if (a==-1 || b==-1) {
+		logger.error("bad format in db");
+	    }
+	    else {
+		key=lines[i].substring(a+1, b);
+		value=lines[i].substring(b+1);
+		logger.debug("key="+key+", val="+value);
+		info.addInfo(key, value);
+
+	    }
+	}
+	return info;
+    }
+
+    /** sets all the name-value pairs in info as the content for key key 
+     * TODO - not implemented yet */
+    public boolean setInfo(String key, DBInfo info) {
+	if (db_==null) {
+	    return false;
+	}
+	return true;
+    }
+    /** sets the key value as info 
+     * TODO - not implemented yet */
+    public boolean setInfo (String key, String info) {
+	if (db_==null) {
+	    return false;
+	}
+	return true;
+    }
+    /** deletes the entry for key 
+     * TODO - not implemented yet */
+    public boolean deleteKey(String key) {
+	if (db_==null) {
+	    return false;
+	}
+	return true;
+    }
+
+    // greenstone convenience methods - should these go into a separate class?
+    // yes I think so.
+    /** converts a greenstone OID to internal docnum */
+    public long OID2Docnum(String OID) {
+	DBInfo info = getInfo(OID);
+	if (info != null) {
+	    long real_num = Long.parseLong(info.getInfo("docnum"));
+	    return real_num;
+	}
+	return -1;
+    }
+    /** converts a docnum to greenstone OID */
+    public String docnum2OID(long docnum) {
+	return docnum2OID(Long.toString(docnum));
+    }
+    
+    /** converts a docnum to greenstone OID */
+    public String docnum2OID(String docnum) {
+	DBInfo info = getInfo(docnum);
+	String oid = info.getInfo("section");
+	return oid;
+    }
+
+    /** converts an external id to greenstone OID */
+    public String externalId2OID(String extid) {
+	DBInfo info = getInfo(extid);
+	if (info != null) {
+	    String oid = info.getInfo("section");
+	    return oid;
+	}
+	return null;
+    }
+    /** translates relative oids into proper oids:
+     * .pr (parent), .rt (root) .fc (first child), .lc (last child),
+     * .ns (next sibling), .ps (previous sibling) 
+     * .np (next page), .pp (previous page) : links sections in the order that you'd read the document
+     * a suffix is expected to be present so test before using 
+     */
+    public String translateOID(String oid) {
+
+	int p = oid.lastIndexOf('.');
+	if (p != oid.length()-3) {
+	    logger.info("translateoid error: '.' is not the third to last char!!");
+	    return oid;
+	}
+	
+	String top = oid.substring(0, p);
+	String suff = oid.substring(p+1);
+	// just in case we have multiple extensions, we must translate
+	// we process inner ones first
+	if (OID.needsTranslating(top)) {
+	    top = translateOID(top);
+	}
+	if (suff.equals("pr")) {
+	    return OID.getParent(top);
+	} 
+	if (suff.equals("rt")) {
+	    return OID.getTop(top);
+	} 
+	if (suff.equals("np")) {
+	    // try first child
+	    String node_id = translateOID(top+".fc");
+	    if (!node_id.equals(top)) {
+		return node_id;
+	    }
+	    // try next sibling
+	    node_id = translateOID(top+".ns");
+	    if (!node_id.equals(top)) {
+		return node_id;
+	    }
+	    // otherwise we keep trying parents sibling
+	    String child_id = top;
+	    String parent_id = OID.getParent(child_id);
+	    while(!parent_id.equals(child_id)) {
+		node_id = translateOID(parent_id+".ns");
+		if (!node_id.equals(parent_id)) {
+		    return node_id;
+		}
+		child_id = parent_id;
+		parent_id = OID.getParent(child_id);
+	    }
+	    return top; // we couldn't get a next page, so just return the original
+	} 
+	if (suff.equals("pp")) {
+	    String prev_sib = translateOID(top+".ps");
+	    if (prev_sib.equals(top)) {
+		// no previous sibling, so return the parent
+		return OID.getParent(top);
+	    }
+	    // there is a previous sibling, so its either this section, or the last child of the last child..
+	    String last_child = translateOID(prev_sib+".lc");
+	    while (!last_child.equals(prev_sib)) {
+		prev_sib = last_child;
+		last_child = translateOID(prev_sib+".lc");
+	    }
+	    return last_child;
+	} 
+	
+	int sibling_num = 0;
+	if (suff.equals("ss")) {
+	    // we have to remove the sib num before we get top
+	    p = top.lastIndexOf('.');
+	    sibling_num = Integer.parseInt(top.substring(p+1));
+	    top = top.substring(0, p);
+	}
+	
+	// need to get info out of gdbm db -
+	String doc_id = top;
+	if (suff.endsWith("s")) {
+	    doc_id = OID.getParent(top);
+	    if (doc_id.equals(top)) {
+		// i.e. we are already at the top
+		return top;
+	    }
+	}
+	DBInfo info = getInfo(doc_id);
+	if (info==null) {
+	    logger.info("info is null!!");
+	    return top;
+	}
+	
+	String contains = info.getInfo("contains");
+	if (contains.equals("")) {
+	    // something is wrong
+	    return top;
+	}
+	contains = contains.replaceAll("\"", doc_id);
+	String [] children = contains.split(";");
+	if (suff.equals("fc")) {
+	    return children[0];
+	} else if (suff.equals("lc")) {
+	    return children[children.length-1];
+	} else {
+	    if (suff.equals("ss")) {
+		return children[sibling_num-1];
+	    }
+	    // find the position that we are at.
+	    int i=0;
+	    while (i<children.length) {
+		if (children[i].equals(top)) {
+		    break;
+		}
+		i++;
+	    }
+	    
+	    if (suff.equals("ns")) {
+		if (i==children.length-1) {
+		    return children[i];
+		}
+		return children[i+1];
+	    } else if (suff.equals("ps")) {
+		if (i==0) {
+		    return children[i];
+		}
+		return children[i-1];
+	    }
+	}
+	
+	return top;
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GS2MacroResolver.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GS2MacroResolver.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GS2MacroResolver.java	(revision 14125)
@@ -0,0 +1,116 @@
+/*
+ *    GS2MacroResolver.java
+ *    Copyright (C) 2005 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.util;
+
+import java.util.ArrayList;
+
+public class GS2MacroResolver 
+    extends MacroResolver 
+{
+
+    protected GDBMWrapper gdbm_src = null;
+    
+    // need to make it not add macros if they are already present
+    public GS2MacroResolver(GDBMWrapper gdbm) {
+	super();
+	gdbm_src = gdbm;
+    }
+
+    
+    public String resolve(String text, String lang, String scope, 
+			  String doc_oid) {
+	if (text == null || text.equals("")) return text;
+	if (scope.equals(SCOPE_TEXT) && text_macros.size()==0) return text;
+	if (scope.equals(SCOPE_META) && metadata_macros.size() ==0) return text;
+	DBInfo node_info = null;
+	DBInfo root_info = null;
+	boolean new_lang = false;
+	if (this.lang == null || !this.lang.equals(lang) ) {
+	    new_lang = true;
+	    this.lang = lang;
+	} 
+
+	ArrayList macros;
+	if (scope.equals(SCOPE_TEXT)) {
+	    macros = text_macros;
+	} else {
+	    macros = metadata_macros;
+	}
+	for (int i=0; i<macros.size(); i++) {
+	    String new_text = null;
+	    Macro m = (Macro)macros.get(i);
+	    switch (m.type) {
+	    case TYPE_DICT:
+		if (m.text==null || new_lang) {
+		    Dictionary dict = new Dictionary(m.bundle, lang);
+		    m.text = dict.get(m.key, null);
+		}
+		// we assume that dictionary entries will contain no macros
+		// otherwise we can't cache the answer because it might be 
+		// document specific
+		text = text.replaceAll(m.macro, m.text);
+		break;
+	    case TYPE_TEXT:
+		// make sure we resolve any macros in the text
+		// the (?s) treats the string as a single line, cos . 
+		// doesn't necessarily match line breaks
+		if (text.matches("(?s).*"+m.macro+".*")) {
+		    if (m.resolve) {
+			new_text = this.resolve(m.text, lang, scope, doc_oid);
+		    } else {
+			new_text = m.text;
+		    }
+		    text = text.replaceAll(m.macro, new_text);
+		}
+		break;
+	    case TYPE_META:
+		if (text.matches(".*"+m.macro+".*")) {
+		    if (node_info == null) {
+			node_info = gdbm_src.getInfo(doc_oid);
+			if (node_info == null) {
+			    break;
+			}
+		    }
+		    new_text = node_info.getInfo(m.text);
+		    if (new_text == null || new_text.equals("")) {
+			// try the root node
+			if (root_info == null && !OID.isTop(doc_oid)) {
+			    root_info = gdbm_src.getInfo(OID.getTop(doc_oid));
+			}
+			if (root_info == null) break;
+			new_text = root_info.getInfo(m.text);
+		    }
+		    if (new_text != null) {
+			if (m.resolve) {
+			    new_text = this.resolve(new_text, lang, scope, doc_oid);
+			}
+			text = text.replaceAll(m.macro, new_text);
+		    }
+		    
+		}
+		
+		break;
+	    } // switch
+	   
+	}
+	return text;
+	
+    }
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSConstants.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSConstants.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSConstants.java	(revision 14125)
@@ -0,0 +1,15 @@
+package org.greenstone.gsdl3.util;
+
+/** these constants are used for servlet args, and config variables */
+public class GSConstants {
+
+    public static final String GSDL3_HOME = "gsdl3_home";
+    public static final String INTERFACE_NAME = "interface_name";
+    public static final String SITE_NAME = "site_name";
+    public static final String LIBRARY_NAME = "library_name";
+    public static final String DEFAULT_LANG = "default_lang";
+
+
+    public static final String META_RELATION_SEP = "_";
+    public static final String META_SEPARATOR_SEP = "*";
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSEntityResolver.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSEntityResolver.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSEntityResolver.java	(revision 14125)
@@ -0,0 +1,50 @@
+package org.greenstone.gsdl3.util;
+
+
+import org.xml.sax.InputSource;
+import org.xml.sax.EntityResolver;
+import java.io.File;
+import java.net.URL;
+
+import org.apache.log4j.*;
+
+// uses a class loader to find entities
+// The class loader to use can be set by setClassLoader(), otherwise it will use the class loader that loaded itself. For the Tomcat webapp, this will be the webapp class loader, not the system class loader. the webapp classloader knows about the classes in the WEB-INF/classes dir, the system classloader knows about the ones on the classpath. The system class loader is a parent to web app classloader, so this will be used as well.
+
+public class GSEntityResolver implements EntityResolver {
+
+    ClassLoader class_loader = null;
+    
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.util.GSEntityResolver.class.getName());
+
+    public void setClassLoader(ClassLoader loader) {
+	this.class_loader = loader;
+    }
+    
+    public InputSource resolveEntity (String public_id, String system_id) {
+	
+	logger.debug("entity resolver for "+system_id);
+	String temp_id = system_id;
+	if (temp_id.startsWith("file://")) {
+	    File f = new File(system_id);
+	    if (f.exists()) {
+		return new InputSource(system_id);
+	    } else {
+		temp_id = temp_id.substring(temp_id.lastIndexOf("/")+1);
+	    }
+	} else {
+	    if (temp_id.indexOf("/")!= -1) {
+		temp_id = temp_id.substring(temp_id.lastIndexOf("/")+1);
+	    }
+	}
+	// try using a class loader
+	if (this.class_loader==null) {
+	    this.class_loader = this.getClass().getClassLoader();
+	}
+	URL url = class_loader.getResource(temp_id);
+	if (url == null) {
+	    return null;
+	}
+	return new InputSource("file://"+url.getFile());
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSFile.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSFile.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSFile.java	(revision 14125)
@@ -0,0 +1,443 @@
+/*
+ *    GSFile.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.util;
+
+import java.io.File; 
+//import org.apache.soap.encoding.soapenc.Base64;
+import org.apache.axis.encoding.Base64;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.lang.ClassLoader; // to find files on the class path
+import java.net.URL;
+import java.util.ArrayList;
+
+import org.apache.log4j.*;
+
+/**
+ * GSFile - utility class for Greenstone.
+ *
+ * all file paths are created here
+ * also has file utility methods
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @version $Revision$
+ * @see File
+ */
+
+public class GSFile {
+
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.util.GSFile.class.getName());
+
+    /**  site config file path */
+    static public String siteConfigFile(String site_home) {
+	return site_home + File.separatorChar+"siteConfig.xml";
+
+    }
+    /**  interface config file path */
+    static public String interfaceConfigFile(String interface_home) {
+	return interface_home + File.separatorChar+"interfaceConfig.xml";
+
+    }
+
+    /** collection directory path */
+    static public String collectDir(String site_home) {
+	return site_home+File.separatorChar+"collect";
+    }
+    
+    
+    /** collection config file path*/
+    static public String collectionConfigFile(String site_home, 
+					      String collection_name) {
+	return collectionConfigFile(collectionBaseDir(site_home, collection_name));
+    }
+    static public String collectionConfigFile(String collection_home) {
+	return collectionEtcDir(collection_home) +
+			File.separatorChar+"collectionConfig.xml";
+
+    }
+    /** collection init file path*/
+    static public String collectionInitFile(String site_home, 
+					    String collection_name) {
+	return site_home+File.separatorChar+"collect"+
+			File.separatorChar+collection_name+
+			File.separatorChar+"etc"+
+			File.separatorChar+"collectionInit.xml";
+
+    }
+
+    /** collection build config file path*/
+    static public String collectionBuildConfigFile(String site_home, 
+						   String collection_name ) {
+	return site_home+File.separatorChar+"collect"+
+			File.separatorChar+collection_name+
+			File.separatorChar+"index"+
+			File.separatorChar+"buildConfig.xml";
+    }
+    /** collection build config file path*/
+    static public String collectionBuildConfigFileBuilding(String site_home, 
+						   String collection_name ) {
+	return collectionBuildConfigFileBuilding(collectionBaseDir(site_home, collection_name));
+    }
+    static public String collectionBuildConfigFileBuilding(String collection_home ) {
+	return collection_home+
+	    File.separatorChar+"building"+
+	    File.separatorChar+"buildConfig.xml";
+    }
+
+    /** XML Transform directory path */
+    static public String xmlTransformDir(String interface_home) {
+	return interface_home+File.separatorChar+"transform";
+    }
+
+    /** collection base directory path */	 
+    static public String collectionBaseDir(String site_home,
+					   String collection_name) {
+	return site_home+File.separatorChar+"collect"+
+	    File.separatorChar+collection_name;
+    }
+    /** collection archive directory path */
+    static public String collectionArchiveDir(String site_home,
+					   String collection_name) {
+	return collectionArchiveDir(collectionBaseDir(site_home, collection_name)); 
+    }
+    static public String collectionArchiveDir(String collection_home) {
+	return collection_home+File.separatorChar+"archives";
+    }
+    
+    /** collection building directory path */	 
+    static public String collectionBuildDir(String site_home,
+					   String collection_name) {
+	return collectionBuildDir(collectionBaseDir(site_home, collection_name));
+    }
+    static public String collectionBuildDir(String collection_home) {
+	return collection_home+File.separator+"building";
+    }
+    /** collection building directory path */	 
+    static public String collectionEtcDir(String site_home,
+					   String collection_name) {
+	return collectionEtcDir(collectionBaseDir(site_home, collection_name));
+    }
+    static public String collectionEtcDir(String collection_home) {
+	return collection_home+File.separator+"etc";
+    }
+
+    /** collection building directory path */	 
+    static public String collectionImportDir(String site_home,
+					   String collection_name) {
+	return collectionImportDir(collectionBaseDir(site_home, collection_name));
+	    
+    }
+    static public String collectionImportDir(String collection_home) {
+	return collection_home + File.separatorChar+"import";
+    }
+    /** collection building directory path */	 
+    static public String collectionIndexDir(String site_home,
+					   String collection_name) {
+	return collectionIndexDir(collectionBaseDir(site_home, collection_name));
+	    
+    }
+    static public String collectionIndexDir(String collection_home) {
+	return collection_home + File.separatorChar+"index";
+    }
+    
+    /** text path (for doc retrieval) relative to collectionBaseDir */
+    static public String collectionTextPath(String index_stem) {
+	return "index"+File.separatorChar+"text"+File.separatorChar+
+	    index_stem;
+    }
+
+    /** index path (for querying) relative to collectionBaseDir */
+    static public String collectionIndexPath(String index_stem,
+					     String index_name) {
+	return "index"+File.separatorChar+index_name+File.separatorChar+
+	    index_stem;
+    }
+    
+    /** collection resources directory path */	 
+    static public String collectionResourceDir(String site_home,
+					       String collection_name) {
+	return collectionResourceDir(collectionBaseDir(site_home, collection_name));
+	    
+    }
+    static public String collectionResourceDir(String collection_home) {
+	return collection_home + File.separatorChar+"resources";
+    }
+
+    /** absolute path for an associated file */
+    static public String assocFileAbsolutePath(String site_home,
+					       String collection_name,
+					       String assoc_file_path,
+					       String filename) {
+	return collectionBaseDir(site_home, collection_name)+
+	    File.separatorChar+"index"+File.separatorChar+
+	    "assoc"+File.separatorChar+assoc_file_path+
+	    File.separatorChar+filename;
+    }
+
+    static public String siteHome(String gsdl3_home, String site_name) {
+	return gsdl3_home + File.separatorChar + "sites" + 
+	    File.separatorChar +site_name;
+    }
+
+    static public String interfaceHome(String gsdl3_home, 
+				       String interface_name) {
+	return gsdl3_home + File.separatorChar + "interfaces" + 
+	    File.separatorChar + interface_name;
+    }
+    
+    static public String siteStylesheetFile(String site_home,
+					    String filename) {
+	return site_home+File.separatorChar + "transform" +
+	    File.separatorChar + filename;
+    }
+    static public String collStylesheetFile(String site_home,
+					    String coll_name,
+					    String filename) {
+	return collectionBaseDir(site_home, coll_name) + File.separatorChar+
+	    "transform" + File.separatorChar + filename;
+    }
+	
+	
+    /** returns the absolute path to a stylesheet 
+     * stylesheets are looked for in the following places, in the 
+     * following order:
+     * current collection, current site, current interface, base interfaces
+     * returns null  if the file cannot be found 
+     *
+     * this is not so good because sites may be on a different computer */
+    static public String stylesheetFile(String gsdl3_home,
+					String site_name,
+					String collection,
+					String interface_name,
+					ArrayList base_interfaces,
+					String filename) {
+
+	String site_home = siteHome(gsdl3_home, site_name);
+	// try collection first
+	File stylesheet = null;
+	if (!collection.equals("")) {
+	    
+	    String coll_home = collectionBaseDir(site_home, collection);
+	    stylesheet = new File(coll_home +File.separatorChar+
+				  "transform"+File.separatorChar+filename);
+	    if (stylesheet.exists()) {
+		return stylesheet.getPath();
+	    }
+	}
+	
+	// try site one next	
+	stylesheet = new File(site_home +File.separatorChar+
+			      "transform"+File.separatorChar+filename);
+	if (stylesheet.exists()) {
+	    return stylesheet.getPath();
+	}
+	
+	// try current interface
+	String interface_home = interfaceHome(gsdl3_home, 
+					      interface_name);
+	stylesheet = new File(interface_home+File.separatorChar+
+			      "transform"+File.separatorChar+filename);
+	if (stylesheet.exists()) {
+	    return stylesheet.getPath();
+	}
+	// try base interface
+	if (base_interfaces==null || base_interfaces.size()==0) {
+	    return null; // no base interfaces to look for
+	}
+	for (int i=0; i<base_interfaces.size(); i++) {
+	    interface_home = interfaceHome(gsdl3_home, (String)base_interfaces.get(i));
+	    stylesheet = new File(interface_home+File.separatorChar+
+				  "transform"+File.separatorChar+filename);
+	    if (stylesheet.exists()) {
+		return stylesheet.getPath();
+	    }
+	}
+	    
+	// still can't find it and we have looked everywhere
+	return null;
+    }
+
+
+    /** base directory for phind data */
+    public static String phindBaseDir(String site_home, String coll_name,
+				      String phind_index) {
+	return site_home + File.separatorChar +
+	    "collect" + File.separatorChar +
+	    coll_name + File.separatorChar +
+	    "index" + File.separatorChar +
+	    "phind"+phind_index;
+    }
+
+    /** the gdbm database file - 
+     * note, need to change extension depending on OS */
+    static public String GDBMDatabaseFile(String site_home, 
+					  String collection_name,
+					  String index_stem) {
+
+	String db_ext = ".ldb";
+	if (Misc.isBigEndian()) {
+	    db_ext = ".bdb";
+	}
+	return site_home + File.separatorChar +
+	    "collect" + File.separatorChar +
+	    collection_name + File.separatorChar +
+	    "index" + File.separatorChar + "text" + File.separatorChar +
+	    index_stem + db_ext;
+
+    }
+
+    // some file utility methods
+
+    /** read in a file and encode it using base64
+     * encoded data returned as a String */
+    static public String base64EncodeFromFile(String in_filename) {
+	byte [] data=null;
+	try {
+	    data = readFile(in_filename);
+	} catch (Exception e) {
+	    logger.error("couldn't read the file");
+	}
+	String encodedString = Base64.encode(data);
+	return encodedString;
+
+    }
+
+    /** decode some base64 data, and write it to the specified file */
+    static public boolean base64DecodeToFile(String data, String out_filename) {
+	try {
+	    byte[] buffer=Base64.decode(data);
+	    writeFile(buffer, out_filename);
+	   
+	} catch (Exception e) {
+	    logger.error("file opening/closing errors"+e.getMessage());
+	    return false;
+	}
+	return true;
+	
+    }
+
+    /** read in a file to a byte array */
+    public static byte[] readFile(String filename) throws IOException {
+	File file = new File(filename);
+	BufferedInputStream bis = new BufferedInputStream(new
+	    FileInputStream(file));
+	int bytes = (int) file.length();
+	byte[] buffer = new byte[bytes];
+	int readBytes = bis.read(buffer);
+	bis.close();
+	return buffer;
+    }
+
+    /** write a byte array to a file */
+    public static void writeFile(byte [] buffer, String filename) throws IOException {
+	File file = new File(filename);
+	BufferedOutputStream bos = new BufferedOutputStream(new
+	    FileOutputStream(file));
+	bos.write(buffer);
+	bos.close();
+    }
+
+    public static boolean deleteFile(File f) {
+
+	if (f.isDirectory()) {
+	    File[] files = f.listFiles();
+	    for (int i=0; files!=null && i<files.length; i++) {
+		deleteFile(files[i]);
+	    }
+
+	}
+	// delete the file or directory
+	return f.delete();
+    }
+    
+    public static boolean copyFile(File source, File destination) {
+	if (!source.isFile()) {
+	    logger.error(source.getPath()+" is not a file!");
+	    return false;
+	}
+	try {
+	    destination.getParentFile().mkdirs();
+	    FileInputStream in = new FileInputStream(source);
+	    FileOutputStream out = new FileOutputStream(destination);
+	    int value = 0;
+	    while((value = in.read()) != -1) {
+		out.write(value);
+	    }
+	    in.close();
+	    out.close();
+	} catch (Exception e) {
+	    logger.error("something went wrong copying "+source.getPath()+" to "+destination.getPath());
+	    logger.error("Exception: "+e.getMessage());
+	    return false;
+	}
+
+	return true;
+    }
+    /** Recursively moves the contents of source file to destination,
+     * maintaining paths.
+     * @param source A File representing the directory whose contents you
+     * wish to move.
+     * @param destination A File representing the directory you wish to move
+     * files to.
+     * @return true if successful
+     */
+    public static boolean moveDirectory(File source, File destination) {
+
+	// first try rename
+	if (source.renameTo(destination)) {
+	    return true;
+	}
+
+	// john T. said that this sometimes doesn't work, so you have to copy files manually
+
+	// copied from gatherer Utility class
+	File input[] = source.listFiles();
+	for(int i = 0; i < input.length; i++) {
+	    File output = new File(destination, input[i].getName());
+	    if (input[i].isDirectory()) {
+		moveDirectory(input[i], output);
+	    } else {
+		// Copy the file
+		try {
+		    output.getParentFile().mkdirs();
+		    FileInputStream in = new FileInputStream(input[i]);
+		    FileOutputStream out = new FileOutputStream(output);
+		    int value = 0;
+		    while((value = in.read()) != -1) {
+			out.write(value);
+		    }
+		    in.close();
+		    out.close();
+		    // Delete file
+		    input[i].delete();
+		} catch (Exception e) {
+		    logger.error("exception: "+e.getMessage());
+		    return false;
+		}
+		
+	    }
+	}
+	return true;
+    }
+    
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSFileTest.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSFileTest.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSFileTest.java	(revision 14125)
@@ -0,0 +1,49 @@
+package org.greenstone.gsdl3.util;
+
+import junit.framework.*; 
+import java.io.File;
+
+public class GSFileTest extends TestCase {
+
+    /** what type of test - used by the testing framework */
+    public static final String TEST_ALL_TEST_TYPE="UNIT";
+
+    public GSFileTest(String name) {
+	super(name);
+    }
+
+    /** test suite that dynamically runs all the tests */
+    public static Test suite() {
+	return new TestSuite(GSFileTest.class);
+    }
+
+    public void testBase64Conversion() {
+	
+	// start off with reverse conversion - decode then encode
+	String data = "sdkfjho9w4385khrf9ow834rfia8ufd38rhf9812";
+	File outfile;
+	try {
+	    outfile = File.createTempFile("b64convert_test", "");
+	} catch (java.io.IOException e) {
+	    fail("couldn't create a temporary file in default temp dir");
+	    return;
+	}
+	String filename = outfile.getAbsolutePath();
+	
+	String newdata;
+	if (GSFile.base64DecodeToFile(data, filename)) {
+	    newdata = GSFile.base64EncodeFromFile(filename);
+
+	    assertEquals("decoded/encoded string does not match the origianl",
+			 data, newdata);
+	    // clean up
+	    outfile.delete();
+	} else {
+	    fail("couldn't decode the data string");
+	}
+
+	//try with a real file???
+	
+    }
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSHTML.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSHTML.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSHTML.java	(revision 14125)
@@ -0,0 +1,64 @@
+package org.greenstone.gsdl3.util;
+
+/** GSHTML - provides some convenience methods for dealing
+ * with html
+ */
+public class GSHTML {
+
+    /** make a string html safe */
+    public static String htmlSafe(String input) {
+
+	StringBuffer filtered = new StringBuffer(input.length());
+	char c;
+	for (int i=0; i<input.length(); i++) {
+	    c = input.charAt(i);
+	    if (c == '<') {
+		filtered.append("&lt;");
+	    } else if (c == '>') {
+		filtered.append("&gt;");
+	    } else if (c == '"') {
+		filtered.append("&quot;");
+	    } else if (c == '&') {
+		filtered.append("&amp;");
+	    } else {
+		filtered.append(c);
+	    }
+	}
+	return(filtered.toString());
+    }
+    /** undo the html safe action */
+    public static String htmlUnsafe(String input) {
+	StringBuffer filtered = new StringBuffer(input.length());
+	char c;
+	for (int i=0; i<input.length(); i++) {
+	    c = input.charAt(i);
+	    if (c =='&') {
+		int j=input.indexOf(';', i);
+		String entity = input.substring(i, j);
+		i=j;
+		if (entity.equals("&amp")) {
+		    filtered.append('&');
+		} else if (entity.equals("&lt")){
+		    filtered.append('<');
+		} else if (entity.equals("&gt")){
+		    filtered.append('>');
+		} else if (entity.equals("&quot")) {
+		    filtered.append('"');
+		} // else just ignore it.
+	    } else {
+		filtered.append(c);
+	    }
+
+	}
+	return(filtered.toString());
+    }
+    
+    /** produce a default error page */
+    public static String  errorPage(String error) {
+	String page = "<html><head><Title>GSDL3 Error!</Title></head>\n"+
+	    "<body><h1>Greenstone Error!</h1>"+
+	    "<p/>"+error+"</body></html>";
+	return page;
+    }
+	
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSParams.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSParams.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSParams.java	(revision 14125)
@@ -0,0 +1,102 @@
+package org.greenstone.gsdl3.util;
+
+import java.util.HashMap;
+
+/** keeps track of the interface parameters, and their defaults */
+public class GSParams {
+
+    public static final String ACTION = "a"; // the major type of action- eg query or browse or process
+    public static final String SUBACTION = "sa"; // subtype of action if we want different processing than the default
+    public static final String REQUEST_TYPE = "rt"; // whether the request is just to display the service form, or to actually do a request to the service
+    public static final String RESPONSE_ONLY = "ro"; // if == 1 do the request and pass back the response xml - no page formatting
+    public static final String OUTPUT = "o"; // if processing is to be done, what type of output - html/xml/other??
+    public static final String SERVICE = "s"; // the name of the service
+    public static final String CLUSTER = "c";   // these two are the same
+    public static final String COLLECTION = "c"; 
+    public static final String LANGUAGE = "l";
+    public static final String DOCUMENT = "d";
+    public static final String DOCUMENT_TYPE = "dt";
+    public static final String RESOURCE = "r";
+    public static final String PROCESS_ID = "pid"; // if a request wasn't completed, this identifies the request - used when asking for a status update
+    
+    public static final String SIBLING = "sib"; // this should not be in here
+    // internal configure args
+    public static final String SYSTEM_SUBSET = "ss";
+    public static final String SYSTEM_CLUSTER = "sc";
+    public static final String SYSTEM_MODULE_NAME = "sn";
+    public static final String SYSTEM_MODULE_TYPE = "st";
+
+    public static final String EXPAND_DOCUMENT = "ed";
+    public static final String EXPAND_CONTENTS = "ec";
+    protected HashMap param_map = null;
+    
+    public GSParams() {
+	this.param_map = new HashMap(30);
+
+	// add in all the standard params
+	addParameter(ACTION, false); 
+	addParameter(SUBACTION,  false); 
+	addParameter(REQUEST_TYPE,  false);
+	addParameter(RESPONSE_ONLY,  false);
+	addParameter(CLUSTER,  false); // we don't want to save collection 
+	//addParameter(COLLECTION); 
+	addParameter(LANGUAGE,  true); 
+	addParameter(DOCUMENT,  true); 
+	addParameter(RESOURCE,  true); 
+	addParameter(OUTPUT, false); 
+	addParameter(SERVICE, false); 
+	addParameter(PROCESS_ID, true); 
+	addParameter(SYSTEM_SUBSET, false);
+	addParameter(SYSTEM_CLUSTER, false);
+	addParameter(SYSTEM_MODULE_NAME, false);
+	addParameter(SYSTEM_MODULE_TYPE, false);
+	addParameter(SIBLING, false);
+	addParameter(DOCUMENT_TYPE, true);
+	addParameter(EXPAND_DOCUMENT, false);
+	addParameter(EXPAND_CONTENTS, false);
+ 	//addParameter();
+	// ugly hack so we don't save the extlink param
+	addParameter("s0.ext", false);
+    }
+    
+    public boolean addParameter(String name, boolean save) {
+	return addParameter(name, "", save);
+    }
+    
+    public boolean addParameter(String name, String default_value, boolean save) {
+	if (this.param_map.containsKey(name)) {
+	    // already there so could not add
+	    return false;
+	}
+
+	this.param_map.put(name, new Param(default_value, save));
+	return true;
+    }
+	
+    public boolean setParamDefault(String name, String default_value) {
+	Param p = (Param)this.param_map.get(name);
+	if (p==null) return false;
+	p.default_value = default_value;
+	return true;
+    }
+    
+    public boolean shouldSave(String name) {
+	if (name.startsWith("p.")) return false;
+	Param p = (Param)this.param_map.get(name);
+	if (p== null) return true; // if things are not in here, always save.
+	return p.save;
+    }
+    
+    private class Param {
+
+	public String default_value = null;
+	public boolean save = true;
+
+	public Param(String default_value, boolean save) {
+	    this.default_value = default_value;
+	    this.save = save;
+	}
+    }
+}
+
+    
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSPath.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSPath.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSPath.java	(revision 14125)
@@ -0,0 +1,150 @@
+/*
+ *    GSPath.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.util;
+
+/**
+ * GSPath - utility class for greenstone
+ *
+ * modifies and examines message address paths and names
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @version $Revision$
+ *
+ */
+
+public class GSPath {
+
+    /** adds new_link to the end of path
+     *
+     * @return the new path
+     */
+    static public String appendLink(String path, String new_link) {
+	if (path.equals("")) {
+	    return new_link;
+	}
+	return path +"/"+new_link;
+    }
+
+    /** adds new_link to the front of path
+     *
+     * @return the new path
+     */
+    static public String prependLink(String path, String new_link) {
+	if (path.equals("")) {
+	    return new_link;
+	}
+	return  new_link+"/"+path;
+    }
+
+    /** replaces the first link in the path with the specified name
+     */
+    static public String replaceFirstLink(String path, String new_first_link) {
+	path = removeFirstLink(path);
+	path = prependLink(path, new_first_link);
+	return path;
+
+    }
+    /** returns the first name in the path
+     *
+     */
+    static public String getFirstLink(String path) {
+
+	int i = path.indexOf("/");
+	if (i==0) { // have a '/' on the front
+	    path = path.substring(1);
+	    i= path.indexOf("/");
+	}
+	if (i==-1) { // '/' not found
+	    return path;
+	}
+	
+	return path.substring(0,i);
+    }
+
+    /** removes the first name in the path
+     *
+     * @return the modified path
+     */
+    static public String removeFirstLink(String path) {
+	int i = path.indexOf("/");
+	if (i==0) { // have a '/' on the front
+	    path = path.substring(1);
+	    i= path.indexOf("/");
+	}
+	if (i==-1) { // '/' not found - remove the whole path
+	    return "";
+	}
+	return path.substring(i+1); // remove the '/' char
+    }
+
+    /** removes the last name in the path
+     *
+     * @return the modified path
+     */
+    static public String removeLastLink(String path) {
+	int i = path.lastIndexOf("/");
+	if (i==-1) { // '/' not found - remove the whole path
+	    return "";
+	}
+	return path.substring(0, i); // remove the '/' char
+    }
+    
+    static public String getLastLink(String path) {
+	int i = path.lastIndexOf("/");
+	if (i==-1) { // '/' not found - return the whole path
+	    return path;
+	}
+	return path.substring(i+1); // remove the last link
+    }
+
+    
+    static public String createPath(String [] links) {
+	String path = links[0];
+	for (int i=1; i<links.length; i++) {
+	    path = appendLink(path, links[i]);
+	}
+	return path;
+    }
+
+    static public int getIndex(String link) {
+	int i = link.indexOf("[");
+	if (i==-1) {
+	    return -1;
+	}
+	int j = link.indexOf("]");
+	String num = link.substring(i+1,j);
+	try {
+	    int index = Integer.parseInt(num);
+	    return index;
+	} catch (Exception e) {
+	    return -1;
+	}
+    }
+
+    static public String removeIndex(String link) {
+	int i = link.indexOf("[");
+	if (i==-1) {
+	    return link;
+	}
+	return link.substring(0, i);
+    }
+
+}
+
+    
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSStatus.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSStatus.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSStatus.java	(revision 14125)
@@ -0,0 +1,36 @@
+package org.greenstone.gsdl3.util;
+
+public class GSStatus {
+
+    // responses for initial request
+    public static final int SUCCESS = 1; // request succeeded
+    public static final int ACCEPTED = 2; // request accepted but not completed
+    public static final int ERROR = 3; // error and process stopped
+
+    // responses for status requests
+    public static final int CONTINUING = 10; // request still continuing
+    public static final int COMPLETED = 11; // request finished
+    public static final int HALTED = 12; // process stopped
+	    
+    // other
+    public static final int INFO = 20; // just an info message that doesnt mean anything
+
+    /** returns true if teh code indicates that a process is no longer running 
+     */
+    public static boolean isCompleted(int code) {
+	if (code == SUCCESS || code == ERROR || code == COMPLETED || code == HALTED) {
+	    return true;
+	} 
+	return false;
+    }
+
+    // there may be other types of error codes
+    public static boolean isError(int code) {
+	if (code == ERROR) {
+	    return true;
+	}
+	return false;
+    }
+
+}
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSXML.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSXML.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSXML.java	(revision 14125)
@@ -0,0 +1,904 @@
+package org.greenstone.gsdl3.util;
+
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Document;
+import org.w3c.dom.Text;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.HashMap;
+import java.util.Vector;
+import java.util.Iterator;
+import java.util.ArrayList;
+
+//import java.util.Locale;
+
+import org.apache.log4j.*;
+
+/** various functions for extracting info out of GS XML */
+public class GSXML {
+
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.util.GSXML.class.getName());
+
+    // greenstone xml elements
+    public static final String MESSAGE_ELEM = "message";
+    public static final String REQUEST_ELEM = "request";
+    public static final String RESPONSE_ELEM = "response";
+    public static final String COLLECTION_ELEM = "collection";
+    public static final String SERVICE_ELEM = "service";
+    public static final String CLUSTER_ELEM = "serviceCluster";
+    public static final String SITE_ELEM = "site";
+    public static final String PARAM_ELEM = "param";
+    public static final String PARAM_OPTION_ELEM = "option";
+    public static final String CONTENT_ELEM = "content";
+    public static final String RESOURCE_ELEM = "resource";
+    public static final String DOCUMENT_ELEM = "document";
+    public static final String METADATA_ELEM = "metadata";
+    public static final String SERVICE_CLASS_ELEM = "serviceRack";
+    public static final String CLASSIFIER_ELEM = "classifier";
+    public static final String APPLET_ELEM = "applet";
+    public static final String APPLET_DATA_ELEM = "appletData";
+    public static final String CONFIGURE_ELEM = "configure";
+    public static final String STATUS_ELEM = "status";
+    public static final String ERROR_ELEM = "error";
+    public static final String DEFAULT_ELEM = "default";
+    public static final String STYLESHEET_ELEM = "format";//"stylesheet"; // any additional stylesheet stuff is carried in the message inside this elem
+    public static final String FORMAT_ELEM = "format"; // config files use format - should we use this instead of stylesheet??
+    public static final String TERM_ELEM = "term";
+    public static final String SYSTEM_ELEM = "system";
+
+    //config file elems
+    public static final String COLLECTION_CONFIG_ELEM = "collectionConfig";
+    public static final String COLLECTION_BUILD_ELEM = "buildConfig";
+    public static final String COLLECTION_INIT_ELEM = "collectionInit";
+    public static final String RECOGNISE_ELEM = "recognise";
+    public static final String DOC_TYPE_ELEM = "docType";
+    public static final String SEARCH_ELEM = "search";
+    public static final String INDEX_ELEM = "index";
+    public static final String INDEX_STEM_ELEM = "indexStem";
+    public static final String INDEX_OPTION_ELEM = "indexOption";
+    public static final String BROWSE_ELEM = "browse";
+    public static final String DISPLAY_ELEM = "display";
+    public static final String LEVEL_ELEM = "level";
+    public static final String SHORTNAME_ATT = "shortname";
+    public static final String NOTIFY_ELEM = "notify";
+    public static final String NOTIFY_HOST_ATT = "host";
+
+    // elems for the pages to be processed by xslt
+    public final static String PAGE_ELEM = "page";
+    public final static String CONFIGURATION_ELEM = "config";
+    public final static String PAGE_REQUEST_ELEM = "pageRequest";
+    public final static String PAGE_RESPONSE_ELEM = "pageResponse";
+    public final static String PAGE_EXTRA_ELEM = "pageExtra";
+
+    //public final static String DESCRIPTION_ELEM = "description";
+
+    public static final String  ACTION_ELEM = "action";
+    public static final String  SUBACTION_ELEM = "subaction";
+    
+    // add on to another elem type to get a list of that type
+    public static final String LIST_MODIFIER = "List";
+
+    // greenstone xml attributes
+    public static final String NAME_ATT = "name";
+    public static final String TO_ATT = "to";
+    public static final String USER_ID_ATT = "uid";
+    public static final String FROM_ATT = "from";
+    public static final String LANG_ATT = "lang";
+    public static final String TYPE_ATT = "type";
+    public static final String VALUE_ATT = "value";
+    public static final String DEFAULT_ATT = "default";
+    public static final String INFO_ATT = "info";
+    public static final String ACTION_ATT = "action";
+    public static final String SUBACTION_ATT = "subaction";
+    public static final String OUTPUT_ATT = "output";
+    public static final String ADDRESS_ATT = "address";
+    public static final String LOCAL_SITE_ATT = "localSite";
+    public static final String LOCAL_SITE_NAME_ATT = "localSiteName";
+    public static final String STATUS_ERROR_CODE_ATT = "code";
+    public static final String STATUS_PROCESS_ID_ATT = "pid";
+    public static final String PARAM_SHORTNAME_ATT = "shortname";
+    public static final String PARAM_IGNORE_POS_ATT = "ignore";
+    public static final String CLASSIFIER_CONTENT_ATT = "content";
+    public static final String ERROR_TYPE_ATT = "type";
+
+    // document stuff
+    public static final String DOC_TYPE_ATT = "docType";
+    public static final String DOC_NODE_ELEM = "documentNode";
+    public static final String NODE_CONTENT_ELEM = "nodeContent";
+    public static final String NODE_STRUCTURE_ELEM = "nodeStructure";
+    public static final String NODE_ID_ATT = "nodeID";
+    public static final String NODE_NAME_ATT = "nodeName";
+    public static final String NODE_TYPE_ATT = "nodeType";
+    public static final String NODE_RANK_ATT = "rank";
+    public static final String NODE_TYPE_ROOT = "root";
+    public static final String NODE_TYPE_INTERNAL = "internal";
+    public static final String NODE_TYPE_LEAF = "leaf";
+
+    public static final String DOC_TYPE_SIMPLE = "simple";
+    public static final String DOC_TYPE_PAGED = "paged";
+    public static final String DOC_TYPE_HIERARCHY = "hierarchy";
+
+    // classifier stuff
+    public static final String CLASS_NODE_ELEM = "classifierNode";
+    public static final String CLASS_NODE_ORIENTATION_ATT = "orientation";
+    
+    // parameter types
+    public static final String PARAM_TYPE_INTEGER = "integer";
+    public static final String PARAM_TYPE_BOOLEAN = "boolean";
+    public static final String PARAM_TYPE_ENUM_START = "enum";
+    public static final String PARAM_TYPE_ENUM_SINGLE = "enum_single";
+    public static final String PARAM_TYPE_ENUM_MULTI = "enum_multi";
+    public static final String PARAM_TYPE_STRING = "string";
+    public static final String PARAM_TYPE_TEXT = "text";
+    public static final String PARAM_TYPE_MULTI = "multi";
+    public static final String PARAM_TYPE_FILE = "file";
+    public static final String PARAM_TYPE_INVISIBLE = "invisible";
+    // stuff for text strings 
+    public static final String DISPLAY_TEXT_ELEM = "displayItem";
+    // the following are used for the name attributes
+    public static final String DISPLAY_TEXT_NAME = "name";
+    public static final String DISPLAY_TEXT_SUBMIT = "submit";
+    public static final String DISPLAY_TEXT_DESCRIPTION = "description";
+
+    // request types 
+    // get the module description
+    public static final String REQUEST_TYPE_DESCRIBE = "describe";
+    // startup a process 
+    public static final String REQUEST_TYPE_PROCESS = "process";
+    // get the status of an ongoing process
+    public static final String REQUEST_TYPE_STATUS = "status";
+    // system type request - eg reload a collection
+    public static final String REQUEST_TYPE_SYSTEM = "system"; 
+    // page requests to the Receptionist/Actions
+    public static final String REQUEST_TYPE_PAGE = "page"; // used to be cgi
+    // get any format info for a service
+    public static final String REQUEST_TYPE_FORMAT = "format"; 
+    // modify the requests
+    public static final String REQUEST_TYPE_MESSAGING = "messaging";
+
+    // service types
+    public static final String SERVICE_TYPE_QUERY = "query";
+    public static final String SERVICE_TYPE_RETRIEVE = "retrieve";
+    public static final String SERVICE_TYPE_BROWSE = "browse";
+    public static final String SERVICE_TYPE_APPLET = "applet";
+    public static final String SERVICE_TYPE_PROCESS = "process";
+    public static final String SERVICE_TYPE_ENRICH = "enrich";
+
+    // system command types and attributes
+    public static final String SYSTEM_TYPE_CONFIGURE = "configure";
+    public static final String SYSTEM_TYPE_ACTIVATE = "activate";
+    public static final String SYSTEM_TYPE_DEACTIVATE = "deactivate";
+
+    public static final String SYSTEM_SUBSET_ATT = "subset";
+    public static final String SYSTEM_MODULE_TYPE_ATT = "moduleType";
+    public static final String SYSTEM_MODULE_NAME_ATT = "moduleName";
+    
+    // communicator types
+    public static final String COMM_TYPE_SOAP_JAVA = "soap";
+    
+    // error types
+    public static final String ERROR_TYPE_SYNTAX = "syntax";
+    public static final String ERROR_TYPE_SYSTEM = "system";
+    public static final String ERROR_TYPE_INVALID_ID = "invalid_id";
+    public static final String ERROR_TYPE_OTHER = "other";
+
+    // some system wide param names
+    public static final String SUBSET_PARAM = "subset";
+    
+    //for plugin
+    public static final String PLUGIN_ELEM = "plugin";
+    public static final String IMPORT_ELEM = "import";
+    
+    
+    /** takes a list of elements, and returns an array of strings 
+     * of the values of attribute att_name */
+    public static String [] getAttributeValuesFromList(Element list,
+						       String att_name) {
+	
+	NodeList children = list.getChildNodes();
+	
+	int num_nodes = children.getLength();
+	String []ids = new String[num_nodes];
+	for (int i=0; i<num_nodes; i++) {
+	    Element e = (Element)children.item(i);
+	    String id = e.getAttribute(att_name);	    
+	    ids[i] = id;	    
+	}
+	
+	return ids;
+    }
+
+    /** takes a paramList element, and gets a HashMap of name-value pairs 
+     * if deep=true, extracts embedded params, otherwise just top level 
+     * params*/
+    public static HashMap extractParams(Element xml, boolean deep) {
+
+	if (!xml.getNodeName().equals(PARAM_ELEM+LIST_MODIFIER)) {
+	    logger.error("paramList element should have been passed to extractParams, instead it was "+xml.getNodeName());
+	    return null;
+	}
+
+	NodeList params = null;
+	if (deep) { // get all the nested ones
+	    params = xml.getElementsByTagName(PARAM_ELEM);
+	} else { // just get the top  level ones
+	    params = xml.getChildNodes();
+	}
+	HashMap param_map = new HashMap();
+	for (int i=0; i<params.getLength(); i++) {
+	    if (params.item(i).getNodeName().equals(PARAM_ELEM)) {
+		Element param = (Element)params.item(i);
+		String name=param.getAttribute(NAME_ATT);
+		String value=getValue(param); //att or content
+		int pos = name.indexOf('.');
+		if (pos == -1) { // a base param
+		    param_map.put(name, value);
+		} else { // a namespaced param
+		    
+		    String namespace = name.substring(0, pos);
+		    name = name.substring(pos+1);
+		    HashMap map = (HashMap)param_map.get(namespace);
+		    if (map == null) {
+			map = new HashMap();
+			param_map.put(namespace, map);
+		    }
+		    map.put(name, value);
+		}
+	    }
+	}
+	return param_map;
+    }
+
+    /** gets the value att or the text content */
+    public static String getValue(Element e) {
+	String val = e.getAttribute(VALUE_ATT);
+	if (val ==null || val.equals("")) {
+	    // have to get it out of the text
+	    val=getNodeText(e); 
+
+	} else {
+	    // unescape the xml stuff
+	    val = unXmlSafe(val);
+	}
+	return val;
+    }
+
+    /** extracts the text out of a node */
+    public static Node getNodeTextNode(Element param) {
+	param.normalize();
+	Node n = param.getFirstChild();
+	while (n!=null && n.getNodeType() !=Node.TEXT_NODE) {
+	    n=n.getNextSibling();
+	}
+	return n;
+    }
+    
+    /** extracts the text out of a node */
+    public static String getNodeText(Element param) {
+	Node text_node = getNodeTextNode(param);
+	if (text_node == null) {
+	    return "";
+	}
+	return text_node.getNodeValue();
+    }
+
+    public static void setNodeText(Element elem, String text) {
+	Node old_text_node = getNodeTextNode(elem);
+	if (old_text_node != null) {
+	    elem.removeChild(old_text_node);
+	}
+	Text t = elem.getOwnerDocument().createTextNode(text);
+	elem.appendChild(t);
+    }
+	
+    /** add text to a document/subsection  element */
+    public static boolean addDocText(Document owner, Element doc, String text) {
+
+	Element content = owner.createElement(NODE_CONTENT_ELEM);
+	Text t = owner.createTextNode(text);
+	content.appendChild(t);
+	doc.appendChild(content);
+	return true;
+    }
+  
+    /** add an error message, unknown error type */
+    public static boolean addError(Document owner, Element doc, String text) {
+	return addError(owner, doc, text, ERROR_TYPE_OTHER);
+    }
+    /** add an error message */
+    public static boolean addError(Document owner, Element doc, String text,
+				   String error_type) {
+
+	Element content = owner.createElement(ERROR_ELEM);
+	content.setAttribute(ERROR_TYPE_ATT, error_type);
+	Text t = owner.createTextNode(text);
+	content.appendChild(t);
+	doc.appendChild(content);
+	return true;
+    }
+
+    /** add an error message */
+    public static boolean addError(Document owner, Element doc, Throwable error) {
+      return addError(owner, doc, error, ERROR_TYPE_OTHER);
+    }
+    
+    /** add an error message */
+    public static boolean addError(Document owner, Element doc, 
+				   Throwable error, String error_type) {
+	error.printStackTrace();
+	return addError(owner, doc, error.toString(), error_type);
+    }
+
+    public static Element createMetadataParamList(Document owner, Vector meta_values) {
+
+	Element meta_param_list = owner.createElement(PARAM_ELEM+LIST_MODIFIER);
+	Iterator i = meta_values.iterator();
+	while(i.hasNext()) {
+	    String next = (String)i.next();
+	    Element meta_param = owner.createElement(PARAM_ELEM);
+	    meta_param_list.appendChild(meta_param);
+	    meta_param.setAttribute(NAME_ATT, "metadata");
+	    meta_param.setAttribute(VALUE_ATT, next);
+	}
+	return meta_param_list;
+    }
+	
+    /** adds a metadata elem to a list */
+    public static boolean addMetadata(Document owner, Element list, 
+				      String meta_name, String meta_value) {
+	if (meta_value==null || meta_value.equals("")) {
+	    return false;
+	}
+	Element data = owner.createElement(METADATA_ELEM);
+	data.setAttribute(NAME_ATT, meta_name);
+	Text t = owner.createTextNode(meta_value);
+	data.appendChild(t);
+	list.appendChild(data);
+	return true;
+
+    }
+
+    /** copies the metadata out of teh metadataList of 'from' into
+     * the metadataList of 'to' */
+    public static boolean mergeMetadataLists(Node to, Node from) {
+	Node to_meta = getChildByTagName(to, METADATA_ELEM+LIST_MODIFIER);
+	Node from_meta = getChildByTagName(from, METADATA_ELEM+LIST_MODIFIER);
+	
+	if  (from_meta == null) { // nothing to copy
+	    return true;
+	}
+	Document to_owner = to.getOwnerDocument();
+	Node new_from = to_owner.importNode(from_meta, true);
+
+	if (to_meta == null) { // just copy the whole list
+	    to.appendChild(new_from);
+	    return true;
+	}
+	
+	// copy individual elements
+	Node child = new_from.getFirstChild();
+	while ( child != null) {
+	    to_meta.appendChild(child);
+	    child = child.getNextSibling();
+	}
+	return true;
+    }
+	
+    /** copies all the children from from to to */
+    public static boolean mergeElements(Element to, Element from) {
+
+	Document owner = to.getOwnerDocument();
+	Node child = from.getFirstChild();
+	while (child != null) {
+	    to.appendChild(owner.importNode(child, true));
+	    child = child.getNextSibling();
+	}
+	return true;
+    }
+    /** returns the (first) child element with the given name */
+    public static Node getChildByTagName(Node n, String name) {
+
+	Node child = n.getFirstChild();
+	while (child!=null) {
+	    if (child.getNodeName().equals(name)) {
+		return child;
+	    }
+	    child = child.getNextSibling();
+	}
+	return null; //not found
+    }
+    
+    /** returns the (nth) child element with the given name 
+     * index numbers start at 0 */
+    public static Node getChildByTagNameIndexed(Node n, String name, int index) {
+	if (index == -1) {
+	    return getChildByTagName(n, name);
+	}
+	int count = 0;
+	Node child = n.getFirstChild();
+	while (child!=null) {
+	    if (child.getNodeName().equals(name)) {
+		if (count == index) {
+		    return child;
+		} else {
+		    count++;
+		}
+	    }
+	    child = child.getNextSibling();
+	}
+	return null; //not found
+    }
+
+    /** takes an xpath type expression of the form name/name/... 
+	and returns the first node that matches, or null if not found */
+    public static Node getNodeByPath(Node n, String path) {
+	
+	String link = GSPath.getFirstLink(path);
+	path = GSPath.removeFirstLink(path);
+	while (!link.equals("")) {
+	    n = getChildByTagName(n, link);
+	    if (n==null) {
+		return null;
+	    }
+	    link = GSPath.getFirstLink(path);
+	    path = GSPath.removeFirstLink(path);
+	}
+	return n;
+    }
+
+    /** takes an xpath type expression of the form name/name/... 
+     * and returns the first node that matches, or null if not found 
+     * can include [i] indices. index numbers start at 0 */
+    public static Node getNodeByPathIndexed(Node n, String path) {
+	
+	String link = GSPath.getFirstLink(path);
+	int index = GSPath.getIndex(link);
+	if (index != -1) {
+	    link = GSPath.removeIndex(link);
+	}
+	path = GSPath.removeFirstLink(path);
+	while (!link.equals("")) {
+	    n = getChildByTagNameIndexed(n, link, index);
+	    if (n==null) {
+		return null;
+	    }
+	    link = GSPath.getFirstLink(path);
+	    index = GSPath.getIndex(link);
+	    if (index != -1) {
+		link = GSPath.removeIndex(link);
+	    }
+	    path = GSPath.removeFirstLink(path);
+	}
+	return n;
+    }
+
+    public static HashMap getChildrenMap(Node n) {
+	
+	HashMap map= new HashMap();
+	Node child = n.getFirstChild();
+	while (child!=null) {
+	    String name = child.getNodeName();
+	    map.put(name, child);
+	    child = child.getNextSibling();
+	}
+	return map;
+    }
+       
+    public static NodeList getChildrenByTagName(Node n, String name) {
+	MyNodeList node_list = new MyNodeList();
+	Node child = n.getFirstChild();
+	while (child!=null) {
+	    if (child.getNodeName().equals(name)) {
+		node_list.addNode(child);
+	    }
+	    child = child.getNextSibling();
+	}
+	return node_list;
+    }
+	
+
+    /** Duplicates an element, but gives it a new name */
+    public static Element duplicateWithNewName(Document owner, Element element,
+					       String element_name, boolean with_attributes)
+    {
+	return duplicateWithNewNameNS(owner, element, element_name, null, with_attributes);
+    }
+
+    /** Duplicates an element, but gives it a new name */
+    public static Element duplicateWithNewNameNS(Document owner, 
+						 Element element,
+						 String element_name, 
+						 String namespace_uri,
+						 boolean with_attributes)
+    {
+	Element duplicate;
+	if (namespace_uri == null) {
+	    duplicate = owner.createElement(element_name);
+	} else {
+	    duplicate = owner.createElementNS(namespace_uri, element_name);
+	}
+	// Copy element attributes
+	if (with_attributes) {
+	    NamedNodeMap attributes = element.getAttributes();
+	    for (int i = 0; i < attributes.getLength(); i++) {
+		Node attribute = attributes.item(i);
+		duplicate.setAttribute(attribute.getNodeName(), attribute.getNodeValue());
+	    }
+	}
+
+	// Copy element children
+	NodeList children = element.getChildNodes();
+	for (int i = 0; i < children.getLength(); i++) {
+	    Node child = children.item(i);
+	    duplicate.appendChild(owner.importNode(child, true));
+	}
+
+	return duplicate;
+    }
+
+    public static void copyAllChildren(Element to, Element from) {
+
+	Document to_doc = to.getOwnerDocument();
+	Node child = from.getFirstChild();
+	while (child != null) {
+	    to.appendChild(to_doc.importNode(child, true));
+	    child = child.getNextSibling();
+	}
+    }
+    /** returns a basic request message */
+    public static  Element createBasicRequest(Document owner, 
+					      String request_type, String to, 
+					      String lang,
+					      String uid) {
+	Element request = owner.createElement(REQUEST_ELEM);
+	request.setAttribute(TYPE_ATT, request_type);
+	request.setAttribute(LANG_ATT, lang);
+	request.setAttribute(TO_ATT, to);
+	request.setAttribute(USER_ID_ATT, uid);
+	return request;
+    }
+    
+    public static Element createTextElement(Document owner, String elem_name,
+					    String text) {
+	Element e = owner.createElement(elem_name);
+	Text t = owner.createTextNode(text);
+	e.appendChild(t);
+	return e;
+
+    }
+
+    public static Element createDisplayTextElement(Document owner, 
+						   String text_name,
+						   String text) {
+	Element e = owner.createElement(DISPLAY_TEXT_ELEM);
+	e.setAttribute(NAME_ATT, text_name);
+	Text t = owner.createTextNode(text);
+	e.appendChild(t);
+	return e;
+
+    }
+
+
+    public static Element createParameter(Document owner, String name, 
+					  String value) {
+	Element param = owner.createElement(PARAM_ELEM);
+	param.setAttribute(NAME_ATT, name);
+	param.setAttribute(VALUE_ATT, value);
+	return param;
+    }
+
+    public static void addParametersToList(Document owner, Element param_list, 
+					   HashMap params) {
+	Set items = params.entrySet();
+	Iterator i = items.iterator();
+	while(i.hasNext()) {
+	    Map.Entry m = (Map.Entry)i.next();
+	    param_list.appendChild(createParameter(owner, (String)m.getKey(), (String)m.getValue()));
+	}
+	
+    }
+
+    public static Element createParameterDescription(Document owner, 
+						     String id,
+						     String display_name,
+						     String type, 
+						     String default_value,
+						     String []option_ids,
+						     String []option_names) {
+
+	
+	Element p = owner.createElement(PARAM_ELEM);
+	p.setAttribute(NAME_ATT, id);
+	p.setAttribute(TYPE_ATT, type);
+	p.appendChild(createDisplayTextElement(owner, GSXML.DISPLAY_TEXT_NAME, display_name));
+
+	if (default_value != null) {
+	    p.setAttribute(DEFAULT_ATT, default_value);
+	}
+	if (option_ids!=null && option_names!=null) {
+	    for (int i=0; i<option_ids.length; i++) {
+		Element e = owner.createElement(PARAM_OPTION_ELEM);
+		e.setAttribute(NAME_ATT, option_ids[i]);
+		e.appendChild(createDisplayTextElement(owner, GSXML.DISPLAY_TEXT_NAME, option_names[i]));
+		p.appendChild(e);
+	    }
+	}
+	return p;
+    }
+    public static Element createParameterDescription2(Document owner, 
+						     String id,
+						     String display_name,
+						     String type, 
+						     String default_value,
+						     ArrayList option_ids,
+						     ArrayList option_names) {
+
+	
+	Element p = owner.createElement(PARAM_ELEM);
+	p.setAttribute(NAME_ATT, id);
+	p.setAttribute(TYPE_ATT, type);
+	p.appendChild(createDisplayTextElement(owner, GSXML.DISPLAY_TEXT_NAME, display_name));
+	if (default_value != null) {
+	    p.setAttribute(DEFAULT_ATT, default_value);
+	}
+	if (option_ids!=null && option_names!=null) {
+	    for (int i=0; i<option_ids.size(); i++) {
+		Element e = owner.createElement(PARAM_OPTION_ELEM);
+		e.setAttribute(NAME_ATT, (String)option_ids.get(i));
+		e.appendChild(createDisplayTextElement(owner, GSXML.DISPLAY_TEXT_NAME, (String)option_names.get(i)));
+		p.appendChild(e);
+	    }
+	}
+	return p;
+    }
+
+
+    /** returns the element parent/node_name[@attribute_name='attribute_value']
+     */
+    public static Element getNamedElement(Element parent, String node_name,
+					  String attribute_name, 
+					  String attribute_value) {
+
+	NodeList children = parent.getChildNodes();
+	for (int i=0; i<children.getLength(); i++) {
+	    Node child = children.item(i);
+	    if (child.getNodeName().equals(node_name)) {
+		if (((Element)child).getAttribute(attribute_name).equals(attribute_value))
+		    return (Element)child;
+	    }
+	}
+	// not found
+	return null;
+    }
+
+    public static int SORT_TYPE_STRING = 0;
+    public static int SORT_TYPE_INT = 1;
+    public static int SORT_TYPE_FLOAT = 2;
+    
+    // sort type: 
+    public static Element insertIntoOrderedList(Element parent_node,
+						String node_name,
+						Element start_from_elem, 
+						Element new_elem, String sort_att,
+						boolean descending)
+    {
+	if (new_elem == null) return null;
+	Element cloned_elem = (Element)parent_node.getOwnerDocument().importNode(new_elem, true);
+	if (start_from_elem == null) {
+	    parent_node.appendChild(cloned_elem);
+	    return cloned_elem;
+	}
+		
+	Node current_node = start_from_elem;
+	String insert_att = cloned_elem.getAttribute(sort_att);
+	String list_att = start_from_elem.getAttribute(sort_att);
+	while ((!descending && list_att.compareTo(insert_att)<0) || (descending && list_att.compareTo(insert_att)>0)) {
+	    current_node = current_node.getNextSibling();
+	    if (current_node == null) break; // end of the list
+	    if (!current_node.getNodeName().equals(node_name)) {
+		continue; // not a valid node
+	    }
+	    list_att = ((Element)current_node).getAttribute(sort_att);
+	}
+	
+	parent_node.insertBefore(cloned_elem, current_node);
+	return cloned_elem;
+    }
+
+
+    /** Returns the appropriate language element from a display elem,
+     display is the containing element, name is the name of the element to 
+     look for, lang is the preferred language, lang_default is the fall back 
+     lang if neither lang is found, will return the first one it finds*/
+    public static String getDisplayText(Element display, String name,
+					String lang, String lang_default) {
+	
+	String def = null;
+	String first = null;
+	NodeList elems = display.getElementsByTagName(DISPLAY_TEXT_ELEM);
+	if (elems.getLength() == 0) return "";
+	for (int i=0; i<elems.getLength(); i++) {
+	    Element e = (Element)elems.item(i);
+	    String n = e.getAttribute(NAME_ATT);
+	    if (name.equals(n)) {
+		String l = e.getAttribute(LANG_ATT);
+		if (lang.equals(l)) {
+		    return getNodeText(e);
+		} else if (lang_default.equals(l)) {
+			def = getNodeText(e);
+		} else if (first == null) {
+		    first = getNodeText(e);
+		}
+	    } else {
+		continue;
+	    }
+	}
+
+	if (def != null) {
+	    return def;
+	}
+	if (first != null) {
+	    return first;
+	}
+	return "";
+    }
+    
+    // replaces < > " ' & in the original with their entities
+    public static String xmlSafe(String original) {
+
+	StringBuffer filtered = new StringBuffer(original.length());
+	char c;
+	for (int i=0; i<original.length(); i++) {
+	    c = original.charAt(i);
+	    if (c == '>') {
+		filtered.append("&gt;");
+	    } else if (c == '<') {
+		filtered.append("&lt;");
+	    } else if (c == '"') {
+		filtered.append("&quot;");
+	    } else if (c == '&') {
+		filtered.append("&amp;");
+	    } else if (c == '\'') {
+		filtered.append("&apos;");
+	    } else {
+		filtered.append(c);
+	    }
+	}
+	return filtered.toString();
+    }
+
+    
+    // replaces < > " ' & entities with their originals
+    public static String unXmlSafe(String original) {
+	
+ 	StringBuffer filtered = new StringBuffer(original.length());
+ 	char c;
+ 	for (int i=0; i<original.length(); i++) {
+ 	    c = original.charAt(i);
+ 	    if (c == '&') {
+ 		int pos = original.indexOf(";", i);
+		String entity = original.substring(i+1, pos);
+		if (entity.equals("gt")) {
+		    filtered.append(">");
+		} else if (entity.equals("lt")) {
+		    filtered.append("<");
+		} else if (entity.equals("apos")) {
+		    filtered.append("'");
+		} else if (entity.equals("amp")) {
+		    filtered.append("&");
+		} else if (entity.equals("quot")) {
+		    filtered.append("\"");
+		} else {
+		    filtered.append("&"+entity+";");
+		}
+		i = pos;
+	    }
+	    else {
+ 		filtered.append(c);
+ 	    }
+ 	}
+ 	return filtered.toString();
+     }
+
+    public static void printXMLNode(Node e) {
+	printXMLNode(e, 0) ;
+    }
+
+    public static String xmlNodeToString(Node e){
+        StringBuffer sb = new StringBuffer("");
+    	xmlNodeToString(sb,e,0); 
+	return sb.toString();
+    }
+
+    private static void xmlNodeToString(StringBuffer sb, Node e, int depth){
+     
+  	for (int i=0 ; i<depth ; i++) 
+	    sb.append(' ') ;
+
+	if (e.getNodeType() == Node.TEXT_NODE){
+	    sb.append("text") ;
+	    return ;
+	}
+	
+	sb.append('<');
+	sb.append(e.getNodeName());
+	NamedNodeMap attrs = e.getAttributes();
+	for (int i = 0; i < attrs.getLength(); i++) {
+	    Node attr = attrs.item(i);
+	    sb.append(' ');  
+	    sb.append(attr.getNodeName());
+	    sb.append("=\"");
+	    sb.append(attr.getNodeValue());   
+	    sb.append('"');
+	}
+
+	NodeList children = e.getChildNodes();
+
+	if (children == null || children.getLength() == 0)
+	    sb.append("/>\n") ;
+	else {
+	    
+	    sb.append(">\n") ;
+	    
+	    int len = children.getLength();
+	    for (int i = 0; i < len; i++) {
+		xmlNodeToString(sb,children.item(i), depth + 1);
+	    }
+	    
+	    for (int i=0 ; i<depth ; i++) 
+		 sb.append(' ') ;
+	    
+	     sb.append("</" + e.getNodeName() + ">\n");
+	}	
+
+
+    }
+   
+    public static void printXMLNode(Node e, int depth) { //recursive method call using DOM API...
+	
+	for (int i=0 ; i<depth ; i++) 
+	    System.out.print(' ') ;
+
+	if (e.getNodeType() == Node.TEXT_NODE){
+	    // shouldn't we actually print the text here????
+	    System.out.println("text") ;
+	    return ;
+	}
+	
+	System.out.print('<');
+	System.out.print(e.getNodeName());
+	NamedNodeMap attrs = e.getAttributes();
+	for (int i = 0; i < attrs.getLength(); i++) {
+	    Node attr = attrs.item(i);
+	    System.out.print(' ');  
+	    System.out.print(attr.getNodeName());
+	    System.out.print("=\"");
+	    System.out.print(attr.getNodeValue());   
+	    System.out.print('"');
+	}
+
+	NodeList children = e.getChildNodes();
+
+	if (children == null || children.getLength() == 0)
+	    System.out.println("/>") ;
+	else {
+	    
+	    System.out.println('>') ;
+	    
+	    int len = children.getLength();
+	    for (int i = 0; i < len; i++) {
+		printXMLNode(children.item(i), depth + 1);
+	    }
+	    
+	    for (int i=0 ; i<depth ; i++) 
+		System.out.print(' ') ;
+	    
+	    System.out.println("</" + e.getNodeName() + ">");
+	}	
+
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSXSLT.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSXSLT.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GSXSLT.java	(revision 14125)
@@ -0,0 +1,99 @@
+package org.greenstone.gsdl3.util;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Document;
+import org.w3c.dom.Text;
+
+import java.util.HashMap;
+import java.util.Vector;
+import java.util.ArrayList;
+
+/** various functions for manipulating Greenstone xslt  */
+public class GSXSLT {
+
+    /** takes a stylesheet Document, and adds in any child nodes from extra_xsl
+     * named templates overwrite any existing one, while match templates are
+just added to the end of teh stylesheet
+     */
+    public static void mergeStylesheets(Document main_xsl, Element extra_xsl) {
+	
+	Element main = main_xsl.getDocumentElement();
+	
+	NodeList children = extra_xsl.getElementsByTagNameNS("http://www.w3.org/1999/XSL/Transform", "template");
+	for (int i=0; i<children.getLength(); i++) {
+	    String name = ((Element)children.item(i)).getAttribute("name");
+	    if (!name.equals("")) {
+		Element old_template = GSXML.getNamedElement(main, "xsl:template", "name", name);
+		if (old_template != null) {
+		    main.removeChild(old_template);
+		}
+	    }
+		
+	    main.appendChild(main_xsl.importNode(children.item(i), true));
+	}
+
+    }
+
+    /** takes any import or include nodes, and creates absolute path names
+     * for the files
+     */
+    public static void absoluteIncludePaths(Document stylesheet, 
+					    String gsdl3_home,
+					    String site_name,
+					    String collection,
+					    String interface_name,
+					    ArrayList base_interfaces) {
+	
+	
+	Element base_node = stylesheet.getDocumentElement();
+	Node child = base_node.getFirstChild();
+	while(child != null) {
+	    String name = child.getNodeName();
+	    if (name.equals("xsl:import") || name.equals("xsl:include")) {
+		((Element)child).setAttribute("href", GSFile.stylesheetFile(gsdl3_home, site_name, collection, interface_name, base_interfaces, ((Element)child).getAttribute("href")));
+	    }
+	    child = child.getNextSibling();
+	}
+	
+    }
+
+    /** 
+     * looks through a stylesheet for <xxx:template match='template_name'>
+     * inside this template it looks for any <xxx:value-of select='metadataList/metadata[@name=yyy]> elements, and extracts the metadata names into a Vector
+     */
+    public static Vector extractWantedMetadata(Document stylesheet, String template_name) {
+	
+	Vector metadata = new Vector();
+	Element base_node = stylesheet.getDocumentElement();
+	NodeList templates = base_node.getElementsByTagNameNS("*","template");
+	for (int i=0; i<templates.getLength(); i++) {
+	    Element template = (Element)templates.item(i);
+	    String match_name = template.getAttribute("match");
+	    if (!match_name.equals(template_name)) {
+		continue; // we're only looking for specific templates
+	    }
+	    String mode = template.getAttribute("mode");
+	    if (!mode.equals("")) {   
+		continue; // we only want ones without modes - these are processing ones, not display ones
+	    }
+	    // we have one that we want to look through
+	    NodeList values = template.getElementsByTagNameNS("*", "value-of");
+	    for (int v=0; v<values.getLength(); v++) {
+		String select = ((Element)values.item(v)).getAttribute("select");
+		if (select.startsWith("metadataList/metadata[@name=")) {
+		    String []bits = select.split("'|\"");
+		    // there should be two quotes in teh string, therefore 3 items, and the second one is teh one we want
+		    String name = bits[1];
+		    metadata.add(name);
+		}
+	    }
+	}
+	return metadata;	
+    }
+
+    
+
+}
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GlobalProperties.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GlobalProperties.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/GlobalProperties.java	(revision 14125)
@@ -0,0 +1,66 @@
+package org.greenstone.gsdl3.util;
+
+import java.util.Properties;
+import java.io.File;
+import java.io.InputStream;
+
+import org.apache.log4j.*;
+
+/** holds some global properties for the application. Read from a properties file */
+public class GlobalProperties {
+
+
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.util.GlobalProperties.class.getName());
+    private static Properties properties = null;
+    private static String properties_filename = "global.properties";
+    private static String gsdl3_home = null;
+    private static String gsdl3_web_address = null;
+    
+    // Note, that if the servlet is reloadable, then it is reloaded each time the file is changed.
+    static {
+	//load in the properties
+	properties = new Properties();
+	reload();	
+    }
+    
+    /** get the value of the property 'key'. returns null if not found */
+    public static String getProperty(String key) {
+	return properties.getProperty(key);
+    }
+
+    /** get the value of the property 'key'. 
+     * returns default_value if not found */
+    public static String getProperty(String key, String default_value) {
+	return properties.getProperty(key, default_value);
+    }
+
+    /** some special ones */
+    public static String getGSDL3Home() {
+	return gsdl3_home;
+    }
+
+    public static String getGSDL3WebAddress() {
+	return gsdl3_web_address;
+    }
+    
+    public static void reload() {
+	try {
+	    InputStream in = Class.forName("org.greenstone.gsdl3.util.GlobalProperties").getClassLoader().getResourceAsStream(properties_filename);
+	    if (in != null) {
+		logger.error("loading global properties");
+		properties.load(in);
+		in.close();
+	    } else {
+		logger.error("couldn't load global properties!");
+	    }
+	    gsdl3_home = properties.getProperty("gsdl3.home");
+	    // make sure the path separators are correct
+	    File gs3_file = new File(gsdl3_home);
+	    gsdl3_home = gs3_file.getPath();
+	    gsdl3_web_address = "http://"+ properties.getProperty("tomcat.server")+":"+ properties.getProperty("tomcat.port")+"/"+properties.getProperty("tomcat.context");
+	} catch (Exception e) {
+	    logger.error("Exception trying to reload global.properties: "+e);
+	}
+	
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/MacroResolver.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/MacroResolver.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/MacroResolver.java	(revision 14125)
@@ -0,0 +1,143 @@
+/*
+ *    MacroResolver.java
+ *    Copyright (C) 2005 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.util;
+
+import java.util.ArrayList;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+
+abstract public class MacroResolver {
+
+    public static final String SCOPE_TEXT = "text";
+    public static final String SCOPE_META = "metadata";
+    public static final String SCOPE_ALL = "all";
+
+    public static final int TYPE_TEXT = 0;
+    public static final int TYPE_META = 1;
+    public static final int TYPE_DICT = 2;
+    
+    protected ArrayList text_macros = null;
+    protected ArrayList metadata_macros = null;
+
+    String lang = null;
+
+    public MacroResolver() {
+    	this.text_macros = new ArrayList();
+	this.metadata_macros = new ArrayList();
+    }
+
+    
+    public void setSiteDetails(String site_address, String cluster_name) {
+	if (site_address != null) {
+	    addMacro(TYPE_TEXT, "_httpsite_", site_address, SCOPE_ALL, false);
+	}
+	if (cluster_name != null) {
+	    addMacro(TYPE_TEXT, "_clustername_", cluster_name, SCOPE_ALL, false);
+	}
+    }
+
+    public void addMacro(int type, String macro, String text_or_metadata, String scope, boolean resolve) {
+	Macro m = new Macro();
+	m.type = type;
+	m.macro = macro;
+	m.text = text_or_metadata;
+	m.resolve = resolve;
+	addMacro(m, scope);
+    }
+
+    public void addMacro(int type, String macro, String bundle, String key, String scope, boolean resolve) {
+	Macro m = new Macro();
+	m.type = type;
+	m.macro = macro;
+	m.bundle = bundle;
+	m.key = key;
+	m.resolve = resolve;
+	addMacro(m, scope);
+    }
+    
+    public void addMacros(Element replace_list_elem) {
+	NodeList replaces = replace_list_elem.getElementsByTagName("replace");
+	for (int i=0; i<replaces.getLength(); i++) {
+	    Element e = (Element)replaces.item(i);
+	    String scope = e.getAttribute("scope");
+	    if (scope.equals("")) {
+		scope = SCOPE_ALL;
+	    }
+	    boolean resolve = true;
+	    String resolve_str = e.getAttribute("resolve");
+	    if (resolve_str.equals("false")) {
+		resolve = false;
+	    }
+	    String from = e.getAttribute("macro");
+	    String to = e.getAttribute("text");
+	    if (!to.equals("")) {
+		addMacro(TYPE_TEXT, from, to, scope, resolve);
+	    } else {
+		String meta = e.getAttribute("metadata");
+		if (!meta.equals("")) {
+		    addMacro(TYPE_META, from, meta, scope, resolve);
+		} else {
+		    String key = e.getAttribute("key");
+		    String bundle = e.getAttribute("bundle");
+		    addMacro(TYPE_DICT, from, bundle, key, scope, resolve);
+		}
+                                                                                                             	    } 
+	}
+	
+    }
+
+    protected void addMacro(Macro m, String scope) {
+
+	if (scope.equals(SCOPE_TEXT)) {
+	    this.text_macros.add(m);
+	}
+	else if (scope.equals(SCOPE_META)) {
+	    this.metadata_macros.add(m);
+	}
+	else if (scope.equals(SCOPE_ALL)) {
+	    this.text_macros.add(m);
+	    this.metadata_macros.add(m);
+	    
+	}
+
+    }
+    
+    abstract public String resolve(String text, String lang, String scope, 
+				   String doc_oid);
+    
+    protected class Macro {
+	
+	/** type of replacement: TEXT, METADATA, DICTIONARY */
+	public int type;
+	/** the macro to replace */
+	public String macro = null;
+	/** If text type, holds the text to replace with. If metadata type, holds the metadata name */
+	public String text = null; 
+	/** If dictionary type, holds the key to look up in the dictionary */
+	public String key = null;
+	/** If dictionary type, holds the resource bundle name */
+	public String bundle = null;
+	/** If true, will try to resolve macros in the replacement text */
+	public boolean resolve = true;
+	
+    }
+	
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/Misc.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/Misc.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/Misc.java	(revision 14125)
@@ -0,0 +1,106 @@
+ /*
+ *    Misc.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.util;
+
+import java.util.HashMap;
+import java.util.Set;
+import java.util.Map;
+import java.util.Iterator;
+import java.util.Properties;
+import java.io.InputStream;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+
+/** contains miscellaneous functions */
+public class Misc {
+    
+    public static void printHash(HashMap map) {
+	Set entries = map.entrySet();
+	Iterator i = entries.iterator();
+	while (i.hasNext()) {
+	    Map.Entry m = (Map.Entry)i.next();
+	    String name = (String)m.getKey();
+	    String value = (String)m.getValue();
+	}  
+    }
+    
+    /** Method to determine if the host system is Windows based.
+     * @return a boolean which is true if the platform is Windows, 
+     * false otherwise
+     */
+    public static boolean isWindows() {
+	Properties props = System.getProperties();
+	String os_name = props.getProperty("os.name","");
+	if(os_name.startsWith("Windows")) {
+	    return true;
+	}
+	return false;
+    }
+    
+    public static boolean isWindows9x() {
+        Properties props = System.getProperties();
+        String os_name = props.getProperty("os.name","");
+        if(os_name.startsWith("Windows") && os_name.indexOf("9") != -1) {
+            return true;
+        }
+        return false;
+    }
+
+    /** Method to determine if the host system is MacOS based.
+     * @return a boolean which is true if the platform is MacOS, false otherwise
+     */
+    public static boolean isMac() {
+        Properties props = System.getProperties();
+        String os_name = props.getProperty("os.name","");
+        if(os_name.startsWith("Mac OS")) {
+            return true;
+        }
+        return false;
+    }
+    
+    public static boolean isBigEndian() {
+
+	if (System.getProperty("sun.cpu.endian").equals("big")) {
+	    return true;
+	}
+	return false;
+
+    }
+
+    public static BufferedReader makeHttpConnection(String url_string)
+	throws java.net.MalformedURLException, java.io.IOException {
+	BufferedReader reader = null;
+	URL url = new URL(url_string);
+	HttpURLConnection connection = (HttpURLConnection)url.openConnection();
+	InputStream input = connection.getInputStream();
+	reader = new BufferedReader(new InputStreamReader(input));  
+	return reader;
+    }
+
+    public static void main(String [] args) {
+	isBigEndian();
+    }
+
+}
+
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/MyNodeList.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/MyNodeList.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/MyNodeList.java	(revision 14125)
@@ -0,0 +1,46 @@
+/*
+ *    MyNodeList.java
+ *   
+
+ *    Copyright (C) 2005 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.util;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.util.ArrayList;
+
+public class MyNodeList implements NodeList {
+    private ArrayList node_list = null;
+    
+    public MyNodeList() {
+	node_list = new ArrayList();
+    }
+    public int getLength() {
+	return node_list.size();
+    }
+    
+    public Node item(int i) {
+	if (i<0 || i >= node_list.size()) return null;
+	return (Node)node_list.get(i);
+    }
+    
+    public void addNode(Node n) {
+	node_list.add(n);
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/NZDLParams.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/NZDLParams.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/NZDLParams.java	(revision 14125)
@@ -0,0 +1,25 @@
+package org.greenstone.gsdl3.util;
+
+public class NZDLParams extends GSParams {
+
+    public NZDLParams() {
+	super();
+
+	// now add in all the service ones we will be using
+	addParameter("stem",  true);	
+	addParameter("case",  true);
+	addParameter("index", true);
+	addParameter("matchMode",  true);
+	addParameter("maxDocs",  true);
+	addParameter("query", true);
+	addParameter("level",  true);
+	addParameter("qb",  true); // queryBox
+	addParameter("qm",  true); // queryMode
+	addParameter("qt",  true); // query type
+	addParameter("qfm",  true); // query form mode
+	addParameter("qfn",  true); // query form number of boxes
+	addParameter("ct",  true); // collection type - mg or mgpp
+	
+    }
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/OID.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/OID.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/OID.java	(revision 14125)
@@ -0,0 +1,86 @@
+package org.greenstone.gsdl3.util;
+
+/** utility class to handle greenstone OIDs
+ *
+ * based around OIDtools.h from gsdl
+ */
+public class OID {
+    
+    /** returns everything up to the first dot 
+	if no dot, returns oid */
+    public static String getTop(String oid) {
+	int pos = oid.indexOf('.');
+	if (pos == -1) {
+	    return oid;
+	}
+	return oid.substring(0, pos);
+	
+    }
+    /** returns true is oid is top level (ie has no dots) 
+     returns false for an empty oid */
+    public static boolean isTop(String oid) {
+	if (oid.equals("")) {
+	    return false;
+	}
+	return (oid.indexOf('.')==-1);
+    }
+	
+    /** returns the parent of oid (everything up to last dot) 
+     returns oid if oid has no parent */
+    public static String getParent(String oid) {
+	int pos = oid.lastIndexOf('.');
+	if (pos == -1) {
+	    return oid;
+	}
+	return oid.substring(0, pos);
+    }
+
+    /** returns the full name - replaces all " with parent */
+    public static String translateParent(String oid, String parent) {
+	return oid.replaceAll("\"", parent); 
+    }
+    /** does the opposite to translate_parent */
+    public static String shrinkParent(String oid) {
+	int pos = oid.lastIndexOf('.');
+	if (pos==-1) return oid;
+	return "\""+oid.substring(pos);
+    }
+    /** returns true if oid uses .fc, .lc, .pr, .ns, .ps .rt (root) .ss (specified sibling)*/
+    public static boolean needsTranslating(String oid) {
+	if (oid.length()<4) return false;
+	String tail = oid.substring(oid.length()-3);
+	return (tail.equals(".fc") || tail.equals(".lc") || 
+		tail.equals(".pr") || tail.equals(".ns") || 
+		tail.equals(".ps") || tail.equals(".rt") || 
+		tail.equals(".ss") || tail.equals(".np") ||
+		tail.equals(".pp"));
+    }
+    /** strips suffix from end */
+    public static String stripSuffix(String oid) {
+	String tail = oid.substring(oid.length()-3);
+	while (tail.equals(".fc") || tail.equals(".lc") || 
+	       tail.equals(".pr") || tail.equals(".ns") || 
+	       tail.equals(".ps") || tail.equals(".ss") || 
+	       tail.equals(".np") || tail.equals(".pp") ||
+	       tail.equals(".rt") ) {
+	    if (tail.equals(".ss")) { // have doc.sibnum.ss
+		oid = oid.substring(0, oid.length()-3);
+		int pos = oid.lastIndexOf('.');
+		//strip that too
+		oid = oid.substring(0, pos);
+	    } 
+	    oid = oid.substring(0, oid.length()-3);
+	    tail = oid.substring(oid.length()-3);
+	}
+	
+	return oid;
+    }
+    /** returns true if child is a child of parent 
+     an oid is not a child of itself */
+    public static boolean isChildOf(String parent, String child) {
+	if (parent.equals(child)) {
+	    return false;
+	}
+	return child.startsWith(parent);
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/OIDTest.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/OIDTest.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/OIDTest.java	(revision 14125)
@@ -0,0 +1,94 @@
+package org.greenstone.gsdl3.util;
+
+import junit.framework.*; 
+
+public class OIDTest extends TestCase {
+
+    /** what type of test - used by the testing framework */
+    public static final String TEST_ALL_TEST_TYPE="UNIT";
+
+    private static final String empty = "";
+    private static final String oid1="HASH123";
+    private static final String oid2="HASH123.1";
+    private static final String oid3="HASH123.1.2";
+    private static final String oidfc = oid1+".fc";
+    private static final String oidlc = oid1+".lc";
+    private static final String oidpr = oid1+".pr";
+    private static final String oidns = oid1+".ns";
+    private static final String oidps = oid1+".ps";
+
+    public OIDTest(String name) {
+	super(name);
+    }
+
+    /** test suite that dynamically runs all the tests */
+    public static Test suite() {
+	return new TestSuite(OIDTest.class);
+    }
+
+    public void testGetTop() {
+	
+	assertEquals(oid1, OID.getTop(oid1));
+	assertEquals(oid1, OID.getTop(oid2));
+	assertEquals(empty, OID.getTop(empty));
+    }
+  
+    public void testIsTop() {
+	assertTrue(!OID.isTop(empty));
+	assertTrue(OID.isTop(oid1));
+	assertTrue(!OID.isTop(oid2));
+    }
+
+    public void testGetParent() {
+
+	assertEquals(empty, OID.getParent(oid1));
+	assertEquals(oid1, OID.getParent(oid2));
+	assertEquals(empty, OID.getParent(empty));
+	
+    }
+
+    public void testTranslateParent() {
+	String short_id = "\".1";
+	assertEquals(oid2, OID.translateParent(short_id, oid1));
+	// should return the original oid if its not a shortened form
+	assertEquals(oid2, OID.translateParent(oid2, oid1));
+	
+    }
+
+    public void testShrinkParent() {
+	String short_oid2 = "\".1";
+	String short_oid3 = "\".2";
+
+	assertEquals(oid1, OID.shrinkParent(oid1));
+	assertEquals(short_oid2, OID.shrinkParent(oid2));
+	assertEquals(short_oid3, OID.shrinkParent(oid3));
+    }
+
+    public void testNeedsTranslating() {
+	assertTrue(!OID.needsTranslating(oid1));
+	assertTrue(!OID.needsTranslating(oid2));
+	assertTrue(OID.needsTranslating(oidfc));
+	assertTrue(OID.needsTranslating(oidlc));
+	assertTrue(OID.needsTranslating(oidpr));
+	assertTrue(OID.needsTranslating(oidns));
+	assertTrue(OID.needsTranslating(oidps));
+
+    }
+
+    public void testStripSuffix() {
+	assertEquals(oid1, OID.stripSuffix(oidfc));
+	assertEquals(oid1, OID.stripSuffix(oidlc));
+	assertEquals(oid1, OID.stripSuffix(oidpr));
+	assertEquals(oid1, OID.stripSuffix(oidns));
+	assertEquals(oid1, OID.stripSuffix(oidps));
+    }
+
+    public void testIsChildOf() {
+	assertTrue(OID.isChildOf(oid1, oid2));
+	assertTrue(OID.isChildOf(oid1, oid3));
+	assertTrue(OID.isChildOf(oid2, oid3));
+	assertTrue(!OID.isChildOf(oid3, oid1));
+	assertTrue(!OID.isChildOf(oid1, oid1));
+    }
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/Processing.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/Processing.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/Processing.java	(revision 14125)
@@ -0,0 +1,102 @@
+package org.greenstone.gsdl3.util;
+
+import java.io.InputStreamReader;
+
+import org.apache.log4j.*;
+
+public class Processing {
+
+      static Logger logger = Logger.getLogger(org.greenstone.gsdl3.util.Processing.class.getName());
+ 
+      /** Determine if the given process is still executing. It does this by attempting to throw an exception - not the most efficient way, but the only one as far as I know
+     * @param process the Process to test
+     * @return true if it is still executing, false otherwise
+     */
+    static public boolean processRunning(Process process) {
+	boolean process_running = false;
+
+	try {
+	    process.exitValue(); // This will throw an exception if the process hasn't ended yet.
+	}
+	catch(IllegalThreadStateException itse) {
+	    process_running = true;
+	}
+	catch(Exception exception) {
+	    exception.printStackTrace();	    
+	}
+	return process_running;
+    }
+    
+    static public int runProcess(String  command) {
+	
+	logger.error("executing command "+command);
+	int exit_value = -1;
+	try {
+	    Process prcs = Runtime.getRuntime().exec(command);
+	    
+	    InputStreamReader error_stream = new InputStreamReader( prcs.getErrorStream(), "UTF-8" );
+	    InputStreamReader output_stream = new InputStreamReader( prcs.getInputStream(), "UTF-8"  );
+	    
+	    StringBuffer error_buffer = new StringBuffer();
+	    StringBuffer output_buffer = new StringBuffer();
+	    
+	    while(processRunning(prcs)) {
+		// Hopefully this doesn't block if the process is trying to write to STDOUT.
+		if((error_stream!=null)) {// && error_stream.ready()) { 
+		    while (error_stream.ready()) {
+			error_buffer.append((char)error_stream.read());
+		    }
+		    //error_buffer = get_stream_char(error_stream,error_buffer,bos);
+		}
+		//Hopefully this won't block if the process is trying to write to STDERR
+		/*else if*/ while (output_stream.ready()) {
+		    output_buffer.append((char)output_stream.read());
+		    //output_buffer = get_stream_char(output_stream,output_buffer,bos);
+		}
+		//else {
+		try {
+		    Thread.sleep(100);
+		}
+		catch(Exception exception) {
+		}
+		// }
+	    }
+	    
+	    // Of course, just because the process is finished doesn't
+	    // mean the incoming streams are empty. Unfortunately I've
+	    // got no chance of preserving order, so I'll process the
+	    // error stream first, then the out stream
+	    while(error_stream.ready()) {
+		error_buffer.append((char)error_stream.read());
+		//error_buffer = get_stream_char(error_stream,error_buffer,bos);
+	    }
+	    
+	    while(output_stream.ready()) {
+		output_buffer.append((char)output_stream.read());
+		//output_buffer = get_stream_char(output_stream,output_buffer,bos);
+	    }
+	    
+	    // do something with the messages
+	    logger.error("err>"+error_buffer.toString());
+	    logger.error("out>"+output_buffer.toString());
+	    // Ensure that any messages still remaining in the string buffers are fired off.
+	    // Now display final message based on exit value
+	    
+	    prcs.waitFor(); 
+	    error_stream.close();
+	    output_stream.close();
+	    error_buffer = null;
+	    output_buffer = null;
+	    
+	    exit_value =  prcs.exitValue();
+	} catch (Exception e) {
+	    logger.error(e);
+	    return 1;
+	}
+	return exit_value;
+	
+	
+    }
+   
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/XMLConverter.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/XMLConverter.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/XMLConverter.java	(revision 14125)
@@ -0,0 +1,339 @@
+/*
+ *    XMLConverter.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.util;
+
+// XML classes
+import org.w3c.dom.Document; 
+import org.w3c.dom.Node; 
+import org.w3c.dom.NodeList;
+import org.w3c.dom.NamedNodeMap;
+import org.xml.sax.InputSource;
+import org.xml.sax.EntityResolver;
+import org.apache.xerces.parsers.DOMParser;
+import org.apache.xerces.dom.DocumentImpl; // for new Documents
+
+// other java classes
+import java.io.Reader;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+
+import org.apache.log4j.*;
+
+/** XMLConverter - utility class for greenstone
+ *
+ * parses XML Strings into Documents, converts Nodes to Strings
+ * different parsers have different behaviour - can experiment in here
+ * now we only use xerces
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @version $Revision$
+ *
+ */
+public class XMLConverter {
+
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.util.XMLConverter.class.getName());
+
+    /** xerces parser */
+    protected DOMParser parser = null;
+
+    private boolean outputEscaping = true;
+
+
+     /** the no-args constructor */
+    public XMLConverter() {
+	try {
+	    this.parser = new DOMParser();
+	    this.parser.setFeature("http://xml.org/sax/features/validation", false);
+	    // don't try and load external DTD - no need if we are not validating, and may cause connection errors if a proxy is not set up.
+	    this.parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+	    // a performance test showed that having this on lead to increased 
+	    // memory use for small-medium docs, and not much gain for large 
+	    // docs.
+	    // http://www.sosnoski.com/opensrc/xmlbench/conclusions.html
+	    this.parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", false);
+	} catch (Exception e) {
+	    logger.error(e.getMessage());
+	}
+    }
+
+    /** sets the entity resolver. pass in null to unset it */
+    public void setEntityResolver(EntityResolver er) {
+	this.parser.setEntityResolver(er);
+    }
+	
+    /** returns a DOM Document */
+    public Document getDOM(String in) {
+	    
+	try {
+	    Reader reader = new StringReader(in);
+	    InputSource xml_source = new InputSource(reader);
+	    
+	    this.parser.parse(xml_source);
+	    Document doc = this.parser.getDocument();
+	    
+	    return doc;
+	    
+	} catch (Exception e) {
+	    logger.error(e.getMessage());
+	}
+	return null;
+    }
+  
+    /** returns a DOM Document */
+    public Document getDOM(File in) {
+	try {
+	    FileReader reader = new FileReader(in);
+	    InputSource xml_source = new InputSource(reader);
+	    this.parser.parse(xml_source);
+	    Document doc = this.parser.getDocument();
+	    return doc;
+
+	} catch (Exception e) {
+	    logger.error(e.getMessage(), e);
+	    
+	}
+	return null;
+    }
+
+    /** returns a DOM document */
+    public Document getDOM(File in, String encoding) {
+	try {
+	    
+	    InputStreamReader isr = new InputStreamReader(new FileInputStream(in), encoding);
+	    InputSource xml_source = new InputSource(isr);
+	    
+	    this.parser.parse(xml_source);
+	    Document doc = this.parser.getDocument();
+	    
+	    return doc;
+
+	} catch (Exception e) {
+	    logger.error(e.getMessage());
+	}
+	return null;
+    }
+    
+
+    /** creates a new empty DOM Document */
+    public Document newDOM() {
+	Document doc = new DocumentImpl(); 
+	return doc;
+    }
+
+    /** returns the Node as a String */
+    public String getString(Node xmlNode)
+    {
+	outputEscaping = true;
+	StringBuffer xmlRepresentation = new StringBuffer();
+	getString(xmlNode, xmlRepresentation, 0, false);
+	return xmlRepresentation.toString();
+    }
+
+    /** returns the node as a nicely formatted String - this introduces extra
+     * text nodes if the String is read back in as a DOM, so should only be 
+     * used for printing */
+    public String getPrettyString(Node xmlNode) {
+	
+	outputEscaping = true;
+	StringBuffer xmlRepresentation = new StringBuffer();
+	getString(xmlNode, xmlRepresentation, 0, true);
+	return xmlRepresentation.toString();
+    }
+
+    private void getString(Node xmlNode, StringBuffer xmlRepresentation, 
+			     int depth, boolean pretty)
+    {
+	
+	if (xmlNode == null) {
+	    xmlRepresentation.append("<null>");
+	    return;
+	}
+
+	short nodeType = xmlNode.getNodeType();
+	String nodeName = xmlNode.getNodeName();
+
+	if (nodeType == Node.DOCUMENT_NODE) {
+	    getString(((Document)xmlNode).getDocumentElement(), xmlRepresentation, depth, pretty);
+	    return;
+	}
+	// Handle Element nodes
+	if (nodeType == Node.ELEMENT_NODE) {
+	    if (pretty) {
+		xmlRepresentation.append("\n");
+		for (int i = 0; i < depth; i++) {
+		    xmlRepresentation.append("  ");
+		}
+	    }
+
+	    // Write opening tag
+	    xmlRepresentation.append("<");
+	    xmlRepresentation.append(nodeName);
+	    
+	    // Write the node attributes
+	    NamedNodeMap nodeAttributes = xmlNode.getAttributes();
+	    for (int i = 0; i < nodeAttributes.getLength(); i++) {
+		Node attribute = nodeAttributes.item(i);
+		xmlRepresentation.append(" ");
+		xmlRepresentation.append(attribute.getNodeName());
+		xmlRepresentation.append("=\"");
+		xmlRepresentation.append(attribute.getNodeValue());
+		xmlRepresentation.append("\"");
+	    }
+
+	    // If the node has no children, close the opening tag and return
+	    if (xmlNode.hasChildNodes() == false) {
+		// This produces somewhat ugly output, but it is necessary to compensate
+		// for display bugs in Netscape. Firstly, the space is needed before the
+		// closing bracket otherwise Netscape will ignore some tags (<br/>, for
+		// example). Also, a newline character would be expected after the tag,
+		// but this causes problems with the display of links (the link text
+		// will contain a newline character, which is displayed badly).
+		xmlRepresentation.append(" />");
+		return;
+	    }
+	    
+	    // Close the opening tag
+	    xmlRepresentation.append(">");
+	    
+	    // Apply recursively to the children of this node
+	    // hack for nodes next to text nodes - dont make them pretty
+	    // this is needed for text inside a <pre> element - any new lines 
+	    // or spaces around the span elements show up in the text
+	    NodeList children = xmlNode.getChildNodes();
+	    boolean do_pretty = pretty;
+	    for (int i = 0; i < children.getLength(); i++) {
+		if (children.item(i).getNodeType()==Node.TEXT_NODE) {
+		    do_pretty=false; // if there is a text node amongst the children, do teh following nodes in non-pretty mode - hope this doesn't stuff up something else
+		}
+		getString(children.item(i), xmlRepresentation, depth + 1, do_pretty);
+	    }
+	    
+	    // Write closing tag
+	    if (pretty) {
+		if (xmlRepresentation.charAt(xmlRepresentation.length()-1) == '\n') {
+		    for (int i = 0; i < depth; i++)
+			xmlRepresentation.append("  ");
+		}
+	    }
+	    xmlRepresentation.append("</");
+	    xmlRepresentation.append(nodeName);
+	    xmlRepresentation.append(">");
+	    if (pretty) {
+		xmlRepresentation.append("\n");
+	    }
+	}
+	
+	// Handle Text nodes
+	else if (nodeType == Node.TEXT_NODE) {
+	    String text = xmlNode.getNodeValue();
+
+	    // Perform output escaping, if required
+	    if (outputEscaping) {
+		text = text.replaceAll("&", "&amp;");  // Must be done first!!
+		text = text.replaceAll("<", "&lt;");
+		text = text.replaceAll(">", "&gt;");
+		text = text.replaceAll("\"", "&quot;");
+		text = text.replaceAll("\'", "&apos;");
+	    }
+
+	    // Remove any control-C characters
+	    text = text.replaceAll("" + (char) 3, "");
+	    xmlRepresentation.append(text);
+	}
+
+	// Handle Processing Instruction nodes
+	else if (nodeType == Node.PROCESSING_INSTRUCTION_NODE) {
+	    if (nodeName.equals("javax.xml.transform.disable-output-escaping")) {
+		outputEscaping = false;
+	    }
+	    else if (nodeName.equals("javax.xml.transform.enable-output-escaping")) {
+		outputEscaping = true;
+	    }
+	    else {
+		logger.warn("Unhandled processing instruction " + nodeName);
+	    }
+	}
+	
+	else if (nodeType == Node.COMMENT_NODE) {
+	    String text = xmlNode.getNodeValue();
+	    xmlRepresentation.append("<!-- ");
+	    xmlRepresentation.append(text);
+	    xmlRepresentation.append(" -->");
+	}
+	    
+	    
+	
+	// A type of node that is not handled yet
+	else {
+	    logger.warn("Unknown node type: " + nodeType+" "+getNodeTypeString(nodeType));
+	}
+
+	return;
+    }
+
+    protected static String getNodeTypeString(short node_type) {
+
+	String type = "";
+	switch(node_type) {
+	case Node.ATTRIBUTE_NODE: 
+	    type="ATTRIBUTE_NODE";
+	    break;
+	case Node.CDATA_SECTION_NODE:
+	    type="CDATA_SECTION_NODE";
+	    break;
+	case Node.COMMENT_NODE:
+	    type="COMMENT_NODE";
+	    break;
+	case Node.DOCUMENT_FRAGMENT_NODE:
+	    type="DOCUMENT_FRAGMENT_NODE";
+	    break;
+	case Node.DOCUMENT_NODE:
+	    type="DOCUMENT_NODE";
+	    break;
+	case Node.DOCUMENT_TYPE_NODE:
+	    type="DOCUMENT_TYPE_NODE";
+	    break;
+	case Node.ELEMENT_NODE:
+	    type="ELEMENT_NODE";
+	    break;
+	case Node.ENTITY_NODE:
+	    type="ENTITY_NODE";
+	    break;
+	case Node.ENTITY_REFERENCE_NODE:
+	    type="ENTITY_REFERENCE_NODE";
+	    break;
+	case Node.NOTATION_NODE:
+	    type="NOTATION_NODE";
+	    break;
+	case Node.PROCESSING_INSTRUCTION_NODE:
+	    type="PROCESSING_INSTRUCTION_NODE";
+	    break;
+	case Node.TEXT_NODE:
+	    type="TEXT_NODE";
+	    break;
+	default:
+	    type="UNKNOWN";
+	}
+
+	return type;
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/XMLTransformer.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/XMLTransformer.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/XMLTransformer.java	(revision 14125)
@@ -0,0 +1,197 @@
+/*
+ *    XMLTransformer.java
+ *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the 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 org.greenstone.gsdl3.util;
+
+// XML classes
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.dom.DOMResult;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+// other java classes
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.File;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.Map;
+import java.util.Iterator;
+
+import org.apache.log4j.*;
+
+/** XMLTransformer - utility class for greenstone
+ *
+ * transforms xml using xslt
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @version $Revision$
+ */
+public class XMLTransformer {
+
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.util.XMLTransformer.class.getName());
+
+  /** The transformer factory we're using */
+    TransformerFactory t_factory=null;
+  
+  /**
+   * The no-arguments constructor. 
+   *
+   * Any exceptions thrown are caught internally
+   * 
+   * @see javax.xml.transform.TransformerFactory
+   */
+    public XMLTransformer() {
+
+	// make sure we are using the xalan transformer
+	System.setProperty("javax.xml.transform.TransformerFactory", "org.apache.xalan.processor.TransformerFactoryImpl");
+	try {
+	    this.t_factory = org.apache.xalan.processor.TransformerFactoryImpl.newInstance();
+
+	} catch (Exception e) {
+	    logger.error("exception "+e.getMessage());
+	}
+    }
+
+ 
+	
+  /**
+   * Transform an XML document using a XSLT stylesheet
+   * 
+   * @param stylesheet a filename for an XSLT stylesheet
+   * @param xml_in the XML to be transformed
+   * @return the transformed XML
+   */
+    public String transform(String stylesheet, String xml_in) {
+	
+	try {
+	    // Use the TransformerFactory to process the stylesheet Source and generate a Transformer.
+	    Transformer transformer = this.t_factory.newTransformer(new StreamSource(stylesheet));
+
+	    // Use the Transformer to transform an XML Source and send the output to a Result object.
+	    StringWriter output = new StringWriter();
+
+	    transformer.transform(new StreamSource(new StringReader(xml_in)), new StreamResult(output));
+	    return output.toString();
+	} catch (TransformerConfigurationException e) {
+	    logger.error("couldn't create transformer object: "+e.getMessageAndLocation());
+	    logger.error(e.getLocationAsString());  
+	    return "";
+	} catch (TransformerException e) {
+	    logger.error("couldn't transform the source: " + e.getMessage());
+	    return "";
+	}	
+    }
+
+    public String transformToString(Document stylesheet, Document source) {
+	return transformToString(stylesheet, source, null);
+    }
+    
+    public String transformToString(Document stylesheet, Document source, HashMap parameters) {
+	
+	try {
+	    // Use the TransformerFactory to process the stylesheet Source and generate a Transformer.
+	    Transformer transformer = this.t_factory.newTransformer(new DOMSource(stylesheet));
+	    if (parameters != null) {
+		Set params = parameters.entrySet();
+		Iterator i = params.iterator();
+		while (i.hasNext()) {
+		    Map.Entry m = (Map.Entry)i.next();
+		    transformer.setParameter((String)m.getKey(), m.getValue());
+		}
+	    }
+	    //transformer.setParameter("page_lang", source.getDocumentElement().getAttribute(GSXML.LANG_ATT));
+
+	    
+	    // Use the Transformer to transform an XML Source and send the output to a Result object.
+	    StringWriter output = new StringWriter();
+	    
+	    transformer.transform(new DOMSource(source), new StreamResult(output));
+	    return output.toString();
+	} catch (TransformerConfigurationException e) {
+	    logger.error("couldn't create transformer object: "+e.getMessageAndLocation());
+	    logger.error(e.getLocationAsString());  
+	    return "";
+	} catch (TransformerException e) {
+	    logger.error("couldn't transform the source: " + e.getMessage());
+	    return "";
+	}	
+      }
+
+    public Node transform(Document stylesheet, Document source) {
+	return transform(stylesheet, source, null);
+    }
+
+    public Node transform(Document stylesheet, Document source, HashMap parameters) {
+
+	try {
+	    // Use the TransformerFactory to process the stylesheet Source and generate a Transformer.
+	    Transformer transformer = this.t_factory.newTransformer(new DOMSource(stylesheet));
+	    if (parameters != null) {
+		Set params = parameters.entrySet();
+		Iterator i = params.iterator();
+		while (i.hasNext()) {
+		    Map.Entry m = (Map.Entry)i.next();
+		    transformer.setParameter((String)m.getKey(), m.getValue());
+		}
+	    }
+
+	    DOMResult result = new DOMResult();
+	    transformer.transform(new DOMSource(source), result);
+	    return result.getNode().getFirstChild();
+	} catch (TransformerConfigurationException e) {
+	    logger.error("couldn't create transformer object: "+e.getMessageAndLocation());
+	    logger.error(e.getLocationAsString());  
+	    return null;
+	} catch (TransformerException e) {
+	    logger.error("couldn't transform the source: " + e.getMessage());
+	    return null;
+	}	
+	
+
+    }
+
+    public Node transform(File stylesheet, File source) {
+
+	try {
+	    Transformer transformer = this.t_factory.newTransformer(new StreamSource(stylesheet));
+	    
+	    DOMResult result = new DOMResult();
+	    transformer.transform(new StreamSource(source), result);
+	    return result.getNode().getFirstChild();
+	} catch (TransformerConfigurationException e) {
+	    logger.error("couldn't create transformer object: "+e.getMessageAndLocation());
+	    logger.error(e.getLocationAsString());  
+	    return null;
+	} catch (TransformerException e) {
+	    logger.error("couldn't transform the source: " + e.getMessage());
+	    return null;
+	}	
+    }
+}
+
+ 
Index: /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/XSLTUtil.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/XSLTUtil.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/gsdl3/util/XSLTUtil.java	(revision 14125)
@@ -0,0 +1,148 @@
+package org.greenstone.gsdl3.util;
+
+import java.util.Date;
+import java.util.Locale;
+import java.text.SimpleDateFormat;
+
+import org.apache.log4j.*;
+
+/** a class to contain various static methods that are used by the xslt
+ * stylesheets
+ */
+public class XSLTUtil {
+
+     static Logger logger = Logger.getLogger(org.greenstone.gsdl3.util.XSLTUtil.class.getName());
+
+    /* some tests */
+    public static boolean equals(String s1, String s2) {
+	return s1.equals(s2);
+    }
+    public static boolean notEquals(String s1, String s2) {
+	return !s1.equals(s2);
+    }
+    public static boolean exists(String s1, String s2) {
+	return !s1.equals("");
+    }
+    public static boolean contains(String s1, String s2) {
+	return (s1.indexOf(s2) != -1);
+    }
+    public static boolean startsWith(String s1, String s2) {
+	return s1.startsWith(s2);
+    }
+    public static boolean endsWith(String s1, String s2) {
+	return s1.endsWith(s2);
+    }
+    public static boolean lessThan(String s1, String s2) {
+	return (s1.compareTo(s2) < 0);
+    }
+    public static boolean lessThanOrEquals(String s1, String s2) {
+	return (s1.compareTo(s2) <= 0);
+    }
+    public static boolean greaterThan(String s1, String s2) {
+	return (s1.compareTo(s2) > 0);
+    }
+    public static boolean greaterThanOrEquals(String s1, String s2) {
+	return (s1.compareTo(s2) >= 0);
+    }
+
+    /* some preprocessing functions */
+    public static String toLower(String orig) {
+	return orig.toLowerCase();
+    }
+    public static String toUpper(String orig) {
+	return orig.toUpperCase();
+    }
+
+    public static byte[] toUTF8(String orig) {
+	
+	try {
+	    byte[] utf8 = orig.getBytes("UTF-8");
+	    return utf8;
+	}
+	catch (Exception e){
+	    logger.error("unsupported encoding");
+	    return orig.getBytes();
+	}
+    }
+
+    public static String getNumberedItem(String list, int number) {
+	String [] items = list.split(",", -1);	
+	if (items.length > number) {
+	    return items[number];
+	}
+	return ""; // index out of bounds
+    }
+
+    
+    public static String tidyWhitespace(String original) {
+	
+	if (original==null || original.equals("")) {
+	    return original;
+	}
+	String new_s = original.replaceAll("\\s+", " ");
+	return new_s;
+    }
+
+
+    public static String getInterfaceText(String interface_name, String lang, String key) {
+	return getInterfaceText(interface_name, lang, key, null);
+    }
+    public static String getInterfaceText(String interface_name, String lang, String key, String args_str) {
+	String [] args = null;
+	if (args_str!=null && !args_str.equals("")) {
+	    args = args_str.split(";");
+	}
+	Dictionary dict = new Dictionary("interface_"+interface_name, lang);
+        String result = dict.get(key, args);
+
+	if (result == null && !interface_name.equals("default")) { // not found, try the default interface
+	    dict = new Dictionary("interface_default", lang);
+	    result = dict.get(key, args);
+	}
+	    
+        if (result == null) { // not found
+            return "_"+key+"_";
+        }
+        return result;
+    }
+
+    public static boolean isImage(String mimetype) {
+	if (mimetype.startsWith("image/")) {
+	    return true;
+	}
+	return false;
+    }
+
+    public static String formatDate(String date, String lang) {
+	
+	String in_pattern = "yyyyMMdd";
+	String out_pattern = "dd MMMM yyyy";
+	if (date.length()==6) {
+	    in_pattern = "yyyyMM";
+	}
+	
+	SimpleDateFormat formatter = new SimpleDateFormat(in_pattern, new Locale(lang));
+	try {
+	    Date d = formatter.parse(date);
+	    formatter.applyPattern(out_pattern);
+	    String new_date = formatter.format(d);
+	    return new_date;
+	} catch (Exception e) {
+	    return date;
+	}
+	
+    }
+
+    public static String formatLanguage(String display_lang, String lang) {
+
+	return new Locale(display_lang).getDisplayLanguage(new Locale(lang));
+    }
+
+    public static String cgiSafe(String original, String lang) {
+
+	original = original.replace('&', ' ');
+	original = original.replaceAll(" ", "%20");
+	return original;
+    }
+}
+
Index: /greenstone3/trunk/src/java/org/greenstone/server/BrowserLauncher.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/server/BrowserLauncher.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/server/BrowserLauncher.java	(revision 14125)
@@ -0,0 +1,131 @@
+package org.greenstone.server;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import org.greenstone.gsdl3.util.Misc;
+import org.apache.log4j.*;
+
+public class BrowserLauncher 
+    extends Thread {
+    
+    private String url = "about:blank" ;
+    static Logger logger = Logger.getLogger(org.greenstone.server.BrowserLauncher.class.getName());
+    private String[] default_browsers = new String[]{"firefox","mozilla"};
+    private String command = "";
+    private int state = -1; //0: launch success, 1: launch failed 
+    public final  static int LAUNCHSUCCESS = 0;
+    public final static int LAUNCHFAILED = 1;
+    private String browserPath = ""; 
+
+    public BrowserLauncher(String browserPath, String url) {
+	this.url = url;
+        this.browserPath = browserPath;
+        //use the default browser
+	if (this.browserPath.equals("")){
+	    setBrowserCommand();
+	}
+	else{
+	    this.command = this.browserPath + " " + this.url;
+	}
+    }
+
+    public BrowserLauncher(){
+
+    }
+
+    // we should try and use settings from the settings panel??
+    protected void setBrowserCommand() {
+	if(Misc.isWindows()) {
+	    // we use cmd and start
+	    if (Misc.isWindows9x()) {
+		this.command = StaticStrings.WIN_9X_OPEN_COMMAND;//"command.com /c start \""+url+"\"";
+	    } else {
+		this.command = StaticStrings.WIN_OPEN_COMMAND;//"cmd.exe /c start \"\" \""+url+"\"";
+	    }
+	} else if (Misc.isMac()) {
+	    this.command = StaticStrings.MAC_OPEN_COMMAND; // "open %1"
+	} else {
+	     // we try to look for a browser
+ 	    for (int i=0; i<default_browsers.length; i++) {
+ 		if (isAvailable(default_browsers[i])) {
+ 		    this.command = default_browsers[i] + " %1";
+ 		    break;
+ 		}
+ 	    }
+	}
+
+	this.command = this.command.replaceAll("%1",this.url);
+    }
+
+    protected boolean isAvailable(String program) {
+	try {
+             Runtime run = Runtime.getRuntime();
+             Process process = run.exec("which "+ program);
+             BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
+	     String line = null;
+	     while ((line = br.readLine()) != null){
+		 if (line.indexOf("no "+program) !=-1){
+		     return false;
+		 }
+	     }    	
+	     
+	    return true;
+	} catch (Exception e) {
+	    return false;
+	}
+    }
+
+    public  int getBrowserState(){
+	return state;
+    }
+    
+    public void run() {
+	// Call an external process using the args.
+	if(command.equals("")) {
+	    state = LAUNCHFAILED;
+            logger.error("launching command is empty");
+	    return;
+	}
+	
+        try {
+	    String prog_name = this.command.substring(0,this.command.indexOf(" "));
+	    String lower_name = prog_name.toLowerCase();
+	    if (lower_name.indexOf("mozilla") != -1 || lower_name.indexOf("firefox") != -1) { 
+		logger.info("found mozilla or firefox, trying remote it");
+                // mozilla and netscape, try using a remote command to get things in the same window
+		String new_command = prog_name +" -raise -remote openURL("+url+",new-tab)";
+		logger.info(new_command);
+		Runtime rt = Runtime.getRuntime();
+		Process process = rt.exec(new_command);
+               	state = LAUNCHSUCCESS;
+		int exitCode = process.waitFor();
+		logger.info("ExitCode:" + exitCode);              
+		if (exitCode != 0) { // if Netscape or mozilla was not open
+		    logger.info("couldn't do remote, trying original command");
+                    logger.info(this.command);
+		    process = rt.exec(this.command); // try the original command
+                    state = LAUNCHSUCCESS;
+		    //for some reseaons the following part is not executed somtimes.
+                    exitCode = process.waitFor();
+                    logger.info("ExitCode:" + exitCode);
+		}
+	    } else {
+		logger.info(this.command);
+                Runtime rt = Runtime.getRuntime();
+		Process process = rt.exec(this.command);
+                state = LAUNCHSUCCESS;
+              	//for some reseaons the following part is not executed sometimes.
+              	int exitCode = process.waitFor();
+		logger.info("ExitCode:" + exitCode);
+		
+	    }
+	}
+	catch (Exception e) {
+	    logger.error(e);
+            state = LAUNCHFAILED;
+	}
+	
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/server/RunAnt.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/server/RunAnt.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/server/RunAnt.java	(revision 14125)
@@ -0,0 +1,64 @@
+package org.greenstone.server;
+
+import java.io.IOException;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import org.greenstone.server.StreamGobbler;
+
+import org.apache.log4j.*;
+
+public class RunAnt extends Thread {
+    private String antCmd = "";
+    static Logger logger = Logger.getLogger(org.greenstone.server.RunAnt.class.getName());
+    private int state = -1; //success: 0 error: 1    
+    public static int SUCCESS = 0;
+    public static int FAILED = 1; 
+
+    private String antSuccess = "BUILD SUCCESSFUL";
+    private String antFailed = "BUILD FAILED";
+    private String antFinished = "Total time";
+
+    public void run() {
+	 
+	 try {
+	     state = -1;
+	     Runtime run = Runtime.getRuntime();
+             Process process = run.exec(getAntCmd());
+	     BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
+	     String line = null;
+             while (!(line = br.readLine()).startsWith(antFinished)){
+                 
+		 if (line.equals(antSuccess)){
+		     state = 0;
+		 }
+     
+		 if (line.equals(antFailed)){
+		     state = 1; 
+                  }
+		 logger.info(line);
+	     }    
+	 } catch (Exception e) {
+	     logger.error(e);
+	     state = 1;
+	 } 
+    }
+  
+    public int getAntState(){
+	return state;     
+    }
+    
+    public void setAntCmd(String cmd) {
+	String osName = System.getProperty("os.name");
+      	if (osName.startsWith("Windows")) {
+	    this.antCmd = "ant.bat " + cmd;
+	} else {
+	    this.antCmd = "ant " + cmd;
+	}
+    }
+
+    public String getAntCmd() {
+	return this.antCmd;
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/server/ScriptReadWrite.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/server/ScriptReadWrite.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/server/ScriptReadWrite.java	(revision 14125)
@@ -0,0 +1,102 @@
+package org.greenstone.server;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+public class ScriptReadWrite {
+
+    public ScriptReadWrite() {
+    }
+
+    public ArrayList readInFile(File file) {
+	try {
+	    ArrayList fileLines = new ArrayList();
+	    String oneLine = null;
+	    BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
+	    while ((oneLine = bufferedReader.readLine()) != null) {
+		fileLines.add(oneLine);
+	    }
+	    bufferedReader.close();
+	    return fileLines;
+	} catch (Exception e) {
+	    System.err.println("exception:" + e);
+	    return null;
+	}
+    }
+
+    public void writeOutFile(File file, ArrayList fileLines_in) {
+	try {
+	    PrintWriter printWriter = new PrintWriter(new BufferedWriter(new FileWriter(file)));
+	    for (int i = 0; i < fileLines_in.size(); i++) {
+		printWriter.println(fileLines_in.get(i));
+	    }
+	    printWriter.flush();
+	    printWriter.close();
+	} catch (Exception e) {
+	    System.err.println("exception:" + e);
+	}
+    }
+
+    public ArrayList queryReplace(ArrayList fileLines_ex, String param,
+				  String newValue) {
+
+	String oneLine = null;
+	String newLine = null;
+	String name = null;
+	// int oneLine_length = 0;
+	param = param.trim();
+	// int param_length = param.length();
+
+	for (int i = 0; i < fileLines_ex.size(); i++) {
+	    oneLine = ((String) fileLines_ex.get(i)).trim();
+	    // oneLine_length = oneLine.length();
+	    StringTokenizer st = new StringTokenizer(oneLine, "=");
+	    if (st.hasMoreTokens()) {
+		name = st.nextToken();
+		if (param.equals(name)) {
+		    newLine = param + "=" + newValue;
+		    fileLines_ex.set(i, newLine);
+		    break;
+		}
+	    }
+	}
+	return fileLines_ex;
+    }
+
+    public String existValue(ArrayList fileLines, String querytext) {
+	String retValue = null;
+	String oneline = null;
+	String name = null;
+	// String value=null;
+	// int oneline_length = 0;
+	querytext = querytext.trim();
+	// int querytext_length = querytext.length();
+	for (int i = 0; i < fileLines.size(); i++) {
+	    oneline = ((String) fileLines.get(i)).trim();
+	    // oneline_length = oneline.length();
+	    StringTokenizer st = new StringTokenizer(oneline, "=");
+	    if (st.hasMoreTokens()) {
+		name = st.nextToken();
+		if (querytext.equals(name)) {
+		    if (st.hasMoreTokens()) {
+			retValue = st.nextToken();
+			retValue = retValue.trim();
+			if (retValue.equals("")) {
+			    retValue = null;
+			}
+		    } else {
+			retValue = null;
+		    }
+		    break;
+		}
+	    }
+	}
+	return retValue;
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/server/Server.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/server/Server.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/server/Server.java	(revision 14125)
@@ -0,0 +1,229 @@
+
+package org.greenstone.server;
+
+import java.awt.Dimension;
+import java.awt.Toolkit;
+import java.io.File;
+import java.io.InputStream;
+import java.util.Properties;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import org.apache.log4j.*;
+
+import org.greenstone.gsdl3.util.Dictionary;
+import org.greenstone.gsdl3.util.GlobalProperties;
+
+public class Server {
+     /** Ant command for managing Tomcat */
+    static final private String START_CMD = "start";
+    static final private String RESTART_CMD = "restart";
+    static final private String CONFIGURE_CMD = "configure";
+    static final private String STOP_CMD = "stop";
+
+    public static final int SERVER_STARTED = 0;
+    public static final int SERVER_START_FAILED = 1;
+    public static final int BROWSER_LAUNCHED = 2;
+    public static final int BROWSER_LAUNCH_FAILED = 3; 
+    
+    private int server_state = -1;    
+
+    private boolean configure_required = true;
+
+    public static File build_properties_file;
+    public static Properties build_properties;
+    public static Dictionary dictionary;
+     
+    private ServerControl server_control;    
+
+    static Logger logger = Logger.getLogger(org.greenstone.server.Server.class.getName());
+    
+    public Server(String gsdl3_src_home)
+    {
+	
+	String build_properties_path=gsdl3_src_home+File.separatorChar+"build.properties";
+	this.build_properties_file = new File(build_properties_path);
+	if (!this.build_properties_file.exists()) {
+	    logger.fatal("Can't find build.properties file "+build_properties_path);
+	    System.exit(1);
+	}
+	
+	build_properties = new Properties();
+	reloadBuildProperties();
+	
+	// make it dynamic language
+	this.dictionary = new Dictionary("server", "en", this.getClass().getClassLoader());
+	
+	server_control = new ServerControl(this);
+	
+	String auto_start = build_properties.getProperty(StaticStrings.AUTOSTART_PROPERTY);
+	if (auto_start != null && auto_start.equals("true")) {
+	    restart();
+	}
+	else{
+	    start();
+	}  
+         
+   }
+
+    public int getServerState(){
+	return server_state;
+    }
+
+    private int runAnt(String cmd){
+	RunAnt runAnt = new RunAnt();
+	runAnt.setAntCmd(cmd);
+	runAnt.run();
+   	return runAnt.getAntState();
+    }
+
+
+    public void reconfigRequired(){
+	configure_required = true;
+    }
+
+    public void start() {
+        int state = -1;
+        server_state = -1;
+	server_control.updateControl();
+	stop();
+	
+  	// reconfigure if necessary
+        if (configure_required){
+	    server_control.displayMessage(dictionary.get("ServerControl.Configuring"));
+	    state = runAnt(CONFIGURE_CMD);
+	    
+	   if (state != RunAnt.SUCCESS){
+	       recordError(CONFIGURE_CMD);
+	   }
+	   GlobalProperties.reload(); // properties file may have changed, so reload it
+	   configure_required = false;
+	}
+	else{
+	    recordSuccess(CONFIGURE_CMD); 
+	}
+	
+	server_control.displayMessage(dictionary.get("ServerControl.Starting"));
+        state = runAnt(START_CMD);
+
+	if (state != RunAnt.SUCCESS){
+	    recordError(START_CMD);
+            server_state = SERVER_START_FAILED;  
+            
+	}	            
+	else{
+	    recordSuccess(START_CMD); 
+            server_state = SERVER_STARTED; 
+       	} 
+
+       	server_control.updateControl();
+    }
+    
+    private void recordError(String message){
+        message = dictionary.get("ServerControl.Error",new String[]{message,GlobalProperties.getGSDL3Home()});
+	server_control.displayMessage(message);
+	logger.error(dictionary.get("ServerControl.Failed",new String[]{message}));
+    }
+
+
+    private void recordError(String message, Exception e){
+        message = dictionary.get("ServerControl.Error",new String[]{message,GlobalProperties.getGSDL3Home()});
+	server_control.displayMessage(message);
+	logger.error(dictionary.get("ServerControl.Failed",new String[]{message}),e);
+    }
+
+    private void recordSuccess(String message){
+        message = dictionary.get("ServerControl.Success",new String[]{message});
+	server_control.displayMessage(message);
+	logger.info(message);
+    }
+
+   
+    public void launchBrowser() {
+        server_state = -1;
+        server_control.updateControl();   
+        String message = dictionary.get("ServerControl.LaunchingBrowser");
+    	server_control.displayMessage(message); 
+	String url = GlobalProperties.getGSDL3WebAddress()+ build_properties.getProperty(StaticStrings.DEFAULT_SERVLET_PROPERTY);
+	BrowserLauncher launcher = new BrowserLauncher(build_properties.getProperty(StaticStrings.BROWSER_PATH),url);
+        logger.info(message);
+
+	launcher.start();
+     
+        //wait for a while
+        while(launcher.getBrowserState() == -1){
+            try{
+		Thread.sleep(3000);
+	    }
+	    catch(Exception e){
+		logger.error(e);
+	    }
+         } 
+
+	if (launcher.getBrowserState() != BrowserLauncher.LAUNCHSUCCESS ){
+	    recordError(dictionary.get("ServerControl.LaunchBrowser")); 
+	    server_state = BROWSER_LAUNCH_FAILED; 
+	}
+	else{
+	    recordSuccess(dictionary.get("ServerControl.LaunchBrowser")); 
+	    server_state = BROWSER_LAUNCHED;
+	}    
+        
+	server_control.updateControl();        
+    }
+    
+    public void restart(){
+	start();       
+        if (server_state == SERVER_STARTED){
+	    launchBrowser();
+	}  
+    }
+
+    public void stop() {
+         server_control.displayMessage(dictionary.get("ServerControl.Stopping"));
+	 int state = runAnt(STOP_CMD);
+	
+        if (state != RunAnt.SUCCESS){
+	    recordError(STOP_CMD);
+	}
+	else{
+	    recordSuccess(STOP_CMD);
+	}
+
+    }
+    
+    public  void reloadBuildProperties() {
+	try {
+	    InputStream in = this.getClass().getClassLoader().getResourceAsStream("build.properties");
+	    
+	    if (in != null) {
+		logger.info("loading build properties");
+		build_properties.load(in);
+		in.close();
+	    } else {
+		logger.error("couldn't load build properties!");
+	    }
+	} catch (Exception e) {
+	    logger.error("Exception trying to reload build.properties: "+e);
+	}
+	
+    }
+
+  
+
+    public static void main (String[] args){
+    	if (args.length != 1) {
+	    System.err.println("Usage: java org.greenstone.server.ServerMain <gsdl3 src home> ");
+	    System.exit(1);
+	}
+	
+	File gsdl3_src_dir = new File(args[0]);
+	if (!gsdl3_src_dir.isDirectory()) {
+	    System.err.println("src directory does not exist!");
+	    System.exit(1);
+	}
+	
+	new Server(args[0]);
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/server/ServerControl.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/server/ServerControl.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/server/ServerControl.java	(revision 14125)
@@ -0,0 +1,241 @@
+package org.greenstone.server;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.File;
+import java.util.ArrayList;
+import javax.swing.*;
+import javax.swing.border.*;
+
+import org.greenstone.gsdl3.util.GlobalProperties;
+
+import org.apache.log4j.*;
+/**
+ * This class is to start or restart the library server
+ * 
+ */
+public class ServerControl extends JFrame {
+
+    static Logger logger = Logger.getLogger(org.greenstone.server.ServerControl.class.getName());
+ 
+    /** The dimension of the frame */
+    static final private Dimension FRAME_SIZE = new Dimension(350, 250);
+
+    Color bg_color = Color.white;    
+    
+    /** some components we need to refer to later */
+    private JLabel info_label;
+    private JButton enter_button;
+    private JMenu fMenu;
+    private Server server;
+    private JFrame thisframe;
+    
+    public ServerControl(Server server) {
+	super(Server.dictionary.get("ServerControl.Frame_Title"));
+ 
+	this.server = server;
+        thisframe = this;
+
+	setSize(FRAME_SIZE);
+	setDefaultCloseOperation(EXIT_ON_CLOSE);
+	Dimension screen_size = Toolkit.getDefaultToolkit().getScreenSize();
+	setLocation((screen_size.width - FRAME_SIZE.width) / 2,
+		    (screen_size.height - FRAME_SIZE.height) / 2);
+	setBackground(Color.white);
+        addWindowListener(new MyAdapter()); 
+   
+        JPanel title_panel = new JPanel();
+	title_panel.setLayout(new BorderLayout());
+
+        JLabel title_label = new JLabel();
+        String title = Server.dictionary.get("ServerControl.Title");           
+        title_label.setText(stringToHTML(title)); 
+        title_label.setOpaque(false);	
+	title_label.setHorizontalAlignment(SwingConstants.CENTER);
+        title_label.setFont(new Font("SansSerif",Font.PLAIN,18));
+       
+
+        JLabel version_label = new JLabel();
+        String version = Server.dictionary.get("ServerControl.Version", new String [] {GlobalProperties.getProperty(StaticStrings.GSDL3_VERSION_PROPERTY)}).toLowerCase();
+         
+        version_label.setText(stringToHTML(version)); 
+        version_label.setOpaque(false);	
+	version_label.setHorizontalAlignment(SwingConstants.CENTER);
+        version_label.setFont(new Font("SansSerif",Font.PLAIN,14));
+        
+        title_panel.add(title_label,BorderLayout.CENTER);
+        title_panel.add(version_label,BorderLayout.SOUTH);
+	title_panel.setBackground(bg_color);	
+	title_panel.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));
+
+   	info_label = new JLabel();
+        info_label.setOpaque(false);
+        info_label.setHorizontalAlignment(SwingConstants.LEFT);
+        info_label.setVerticalAlignment(SwingConstants.CENTER);
+        info_label.setFont(new Font("SansSerif",Font.PLAIN,14));
+	info_label.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));	        
+		
+        JPanel button_panel = new JPanel(new FlowLayout(FlowLayout.CENTER));
+	enter_button = new JButton();
+	enter_button.setEnabled(false);
+	enter_button.addActionListener(new EnterButtonListener());
+        enter_button.setText(Server.dictionary.get("ServerControl.EnterLibrary"));
+ 	button_panel.add(enter_button);
+	button_panel.setBackground(bg_color);	
+	button_panel.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));
+
+	getContentPane().setLayout(new BorderLayout());
+	getContentPane().add(title_panel,BorderLayout.NORTH);
+	getContentPane().add(info_label,BorderLayout.CENTER);
+	getContentPane().add(button_panel,BorderLayout.SOUTH);
+	getContentPane().setBackground(bg_color);
+    	setJMenuBar(createMenu());
+	setVisible(true);
+    }
+
+    protected JMenuBar createMenu() {
+	JMenuBar menuBar = new JMenuBar();
+         fMenu = new JMenu(Server.dictionary.get("ServerControl.Menu.File"));
+	JMenuItem iConf = new JMenuItem(Server.dictionary.get("ServerControl.Menu.Settings"));
+	iConf.setBackground(Color.white);
+	iConf.addActionListener(new ActionListener() {
+		public void actionPerformed(ActionEvent ae) {
+		    ServerSettings serverSetting = new ServerSettings(server);
+		}
+	    });
+	
+	JMenuItem iExit = new JMenuItem(Server.dictionary.get("ServerControl.Menu.Exit"));
+	iExit.setBackground(Color.white);
+	iExit.addActionListener(new ActionListener() {
+		public void actionPerformed(ActionEvent ae) {
+		    Thread runInThread = new Thread(new Runnable(){
+			    public void run(){
+				server.stop();
+			    
+			    }
+			},"stop server");
+		    try{
+                        runInThread.start(); 
+		
+		    }
+		    catch(Exception e){
+			logger.error(e);
+		    }    
+		    thisframe.dispose();
+		}
+	    });
+	fMenu.add(iConf);
+	fMenu.add(iExit);
+	fMenu.setEnabled(false);
+	menuBar.add(fMenu);
+	menuBar.setBorder(new BevelBorder(BevelBorder.RAISED));
+	return menuBar;
+    }
+
+    public void updateControl(){
+      	switch (server.getServerState()){
+	case Server.SERVER_STARTED:
+	    {
+		info_label.setText(stringToHTML(Server.dictionary.get("ServerControl.Help_EnterLibrary")));
+		enter_button.setEnabled(true);
+		fMenu.setEnabled(true);
+                break;
+	    }
+	case Server.SERVER_START_FAILED:
+	    {
+		enter_button.setText(stringToHTML(Server.dictionary.get("ServerControl.StartServer")));
+		enter_button.setEnabled(true);
+		fMenu.setEnabled(true);
+		break;	
+	    }
+	case Server.BROWSER_LAUNCHED:
+	    {
+		info_label.setText(stringToHTML(Server.dictionary.get("ServerControl.Help_RestartLibrary")));
+		enter_button.setText(stringToHTML(Server.dictionary.get("ServerControl.RestartLibrary")));
+		thisframe.setState(Frame.ICONIFIED);
+		enter_button.setEnabled(true);
+                fMenu.setEnabled(true);
+		break;
+	    }
+	case Server.BROWSER_LAUNCH_FAILED:
+	    {
+		enter_button.setText(stringToHTML(Server.dictionary.get("ServerControl.EnterLibrary")));
+		enter_button.setEnabled(true);
+		fMenu.setEnabled(true);
+                 break;	
+	    }
+        default:{
+	    enter_button.setEnabled(false);
+	    fMenu.setEnabled(false);
+	}
+	}
+    }
+           
+   
+    public void displayMessage(String message){
+	info_label.setText(stringToHTML("<br>"+message));           
+    }
+    
+    private class MyAdapter extends WindowAdapter{   
+	public void windowClosing(WindowEvent env){
+            Thread runInThread = new Thread(new Runnable(){
+			    public void run(){
+				server.stop();
+				
+			    }
+		},"stop server");
+	    try{
+		runInThread.start(); 
+	    }
+	    catch(Exception e){
+		logger.error(e);
+	    }  
+	    thisframe.dispose();
+	}
+    } 
+
+    private String stringToHTML(String s){
+	return "<html><body>"+s+"</body></html>";	
+    }
+    
+    private class EnterButtonListener
+	implements ActionListener {
+	
+	public void actionPerformed(ActionEvent ev) {
+	    switch (server.getServerState()){
+	    case Server.SERVER_STARTED: case Server.BROWSER_LAUNCH_FAILED:
+		{
+		 Thread runInThread = new Thread(new Runnable(){
+			    public void run(){
+			    server.launchBrowser();
+			    }
+			},"launch browser");
+		    
+		    runInThread.start(); 
+                   break;     
+		}
+	    case Server.SERVER_START_FAILED:
+		{
+		    Thread runInThread = new Thread(new Runnable(){
+			    public void run(){
+				server.start();
+			    }
+			},"start server");
+		    runInThread.start();
+		    break;
+		}  	
+	    case Server.BROWSER_LAUNCHED:
+		{
+		    Thread runInThread = new Thread(new Runnable(){
+			    public void run(){
+				server.restart();
+				  
+			    }
+			},"restart server");
+		    runInThread.start();
+		}  
+	    }   
+	  
+	}
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/server/ServerSettings.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/server/ServerSettings.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/server/ServerSettings.java	(revision 14125)
@@ -0,0 +1,324 @@
+package org.greenstone.server;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import javax.swing.*;
+
+import org.w3c.dom.*;
+
+import org.greenstone.gsdl3.util.GSXML;
+import org.greenstone.gsdl3.util.GlobalProperties;
+import org.greenstone.gsdl3.util.XMLConverter;
+
+import org.apache.log4j.*;
+
+public class ServerSettings extends JDialog
+
+{
+
+    static Logger logger = Logger.getLogger(org.greenstone.server.ServerControl.class.getName());
+    static final int DEFPORT = 8080;
+    JCheckBox autoEnter;
+    JComboBox servlet_combobox;
+    private JSpinner portNumber_spinner = null;
+    private JTextField program_path_field = null;
+    private JButton browse_button = null; 
+    private JRadioButton default_browser_button = null ;
+    private JRadioButton other_browser_button = null;
+    private Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
+
+    static final private Dimension SIZE = new Dimension(300, 350);
+    static final Color bg_color = Color.white; 
+    private int portNum = DEFPORT;
+    private boolean autoStart = false;
+    private String servletDefault = null;
+    private String browserPath = "";
+    private boolean useDefaultBrowser = true;
+
+    private HashMap url_mappings = null;
+    private JDialog self;
+    private Server server;
+     
+    public ServerSettings(Server server) {
+	super((Frame)null, "", true);
+	this.self = this;
+        this.server = server;
+
+        try{
+	    this.portNum = Integer.parseInt(server.build_properties.getProperty(StaticStrings.TOMCAT_PORT_PROPERTY));
+	}
+        catch(Exception e){
+	    logger.error(e);
+	} 
+
+        this.browserPath = server.build_properties.getProperty(StaticStrings.BROWSER_PATH);
+        
+        if (this.browserPath == null || this.browserPath.equals("")){
+	    useDefaultBrowser = true;
+            this.browserPath = "";
+	}
+	else{
+	    useDefaultBrowser = false;
+	}
+
+	String auto_start_str = server.build_properties.getProperty(StaticStrings.AUTOSTART_PROPERTY);
+	if ((auto_start_str.trim()).equals("true")) {
+	    this.autoStart = true;
+	} else {
+	    this.autoStart = false;
+	}
+
+	this.servletDefault = server.build_properties.getProperty(StaticStrings.DEFAULT_SERVLET_PROPERTY).replaceAll("/","");
+
+	setSize(SIZE);
+	setTitle(server.dictionary.get("ServerSettings.Title"));
+
+	setLocation((screen.width - SIZE.width) / 2,
+		    (screen.height - SIZE.height) / 2);
+	setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+
+	JLabel port_label = new JLabel(Server.dictionary.get("ServerSettings.Tomcat_Port"));
+
+	portNumber_spinner = new JSpinner(new SpinnerNumberModel(portNum,1,65535,1));
+	portNumber_spinner.setEditor(new JSpinner.NumberEditor(portNumber_spinner, "#####")); 
+
+	autoEnter = new JCheckBox(server.dictionary.get("ServerSettings.Auto_Start"));
+	
+	if (autoStart) {
+	    autoEnter.setSelected(true);
+	} else {
+	    autoEnter.setSelected(false);
+	}
+	autoEnter.setBackground(bg_color);
+
+	JLabel servlet_label = new JLabel(server.dictionary.get("ServerSettings.Servlet"));
+
+	servlet_combobox = new JComboBox();
+	servlet_combobox.setMaximumRowCount(5);
+	servlet_combobox.setBackground(bg_color);
+
+	File web_xml = new File(GlobalProperties.getProperty(StaticStrings.GSDL3_HOME_PROPERTY) + File.separator + "WEB-INF" + File.separator + "web.xml");
+	XMLConverter converter = new XMLConverter();
+	Document web_config = converter.getDOM(web_xml);
+	if (web_config == null) {
+	    logger.error("web.xml is null! "+web_xml.getAbsolutePath());
+	    return;
+	}
+
+	NodeList servlet_mappings = web_config.getElementsByTagName("servlet-mapping");
+	// make a little map class
+	url_mappings = new HashMap();
+	for (int i = 0; i < servlet_mappings.getLength(); i++) {
+	    Element map = (Element) servlet_mappings.item(i);
+	    Element servlet_name_elem = (Element) GSXML.getChildByTagName(map, "servlet-name");
+	    String name = GSXML.getNodeText(servlet_name_elem);
+	    Element url_pattern_elem = (Element) GSXML.getChildByTagName(map, "url-pattern");
+	    String pattern = GSXML.getNodeText(url_pattern_elem);
+	    // Ignore the Axis servlets
+	    if (!(name.equals("AxisServlet"))) {
+		servlet_combobox.addItem(name.trim());
+		url_mappings.put(name, pattern);
+	    }
+
+	    if (name.equals(servletDefault)) {
+		servlet_combobox.setSelectedItem(name);
+	    }
+	}
+
+	JButton save_button = new JButton(Server.dictionary.get("ServerSettings.OK"));
+	save_button.addActionListener(new SaveActionListener());
+
+	JButton exit_button = new JButton(Server.dictionary.get("ServerSettings.Cancel"));
+	exit_button.addActionListener(new ActionListener() {
+		public void actionPerformed(ActionEvent ev) {
+		    self.dispose();
+		}
+	    });
+
+        JPanel  port_panel = new JPanel();    
+        port_panel.setLayout(new FlowLayout(FlowLayout.LEFT));
+	port_panel.add(port_label);
+	port_panel.add(portNumber_spinner);
+	port_panel.setBackground(bg_color);
+
+        JPanel comb_panel = new JPanel();
+	comb_panel.setLayout(new FlowLayout(FlowLayout.LEFT));
+	comb_panel.add(servlet_label);
+	comb_panel.add(servlet_combobox);
+	comb_panel.setBackground(bg_color);
+
+        
+	JPanel  check_panel = new JPanel(); 
+       	check_panel.setLayout(new FlowLayout(FlowLayout.LEFT));
+        check_panel.add(autoEnter);
+        check_panel.setBackground(bg_color);
+
+	JPanel mid_panel = new JPanel();
+        mid_panel.setLayout(new GridLayout(3,1));
+	mid_panel.add(port_panel);
+	mid_panel.add(check_panel);
+	mid_panel.add(comb_panel);
+	mid_panel.setBackground(bg_color);
+	mid_panel.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));
+
+
+	JPanel browser_panel = new JPanel();
+        browser_panel.setLayout(new GridLayout(4,1));
+        default_browser_button = new JRadioButton(Server.dictionary.get("ServerSettings.DefaultBrowser"));
+        other_browser_button = new JRadioButton(Server.dictionary.get("ServerSettings.OtherBrowser"));
+        other_browser_button.addActionListener(new BrowserSelectionListener());
+        default_browser_button.addActionListener(new BrowserSelectionListener());
+
+	ButtonGroup bg = new ButtonGroup();
+        bg.add(default_browser_button);
+        bg.add(other_browser_button);
+        default_browser_button.setBorder(BorderFactory.createEmptyBorder(5,10,5,0));
+        default_browser_button.setBackground(bg_color);     
+        other_browser_button.setBorder(BorderFactory.createEmptyBorder(5,10,5,0)); 
+        other_browser_button.setBackground(bg_color);
+        JPanel browse_program_panel = new JPanel();     
+        browse_program_panel.setLayout(new BorderLayout());
+        program_path_field = new JTextField(this.browserPath);
+        browse_button = new JButton(Server.dictionary.get("ServerSettings.Browse"));
+	browse_program_panel.add(program_path_field,BorderLayout.CENTER);
+        browse_program_panel.add(browse_button,BorderLayout.EAST);
+        browse_program_panel.setBorder(BorderFactory.createEmptyBorder(5,10,5,0));
+	browse_program_panel.setBackground(bg_color);
+        browser_panel.add(new JLabel(Server.dictionary.get("ServerSettings.ChooseBrowser")));
+        browser_panel.add(default_browser_button);
+	browser_panel.add(other_browser_button);
+        browser_panel.add(browse_program_panel);
+	browser_panel.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));
+        browser_panel.setBackground(bg_color);
+	if (useDefaultBrowser){
+	    default_browser_button.setSelected(true);
+	    program_path_field.setEnabled(false);
+	    browse_button.setEnabled(false); 
+	}
+	else{
+	    other_browser_button.setSelected(true);
+	}
+        browse_button.addActionListener(new BrowseActionListener());       
+        
+        JPanel down_panel = new JPanel();
+	down_panel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
+	down_panel.add(save_button);
+	down_panel.add(exit_button);
+	down_panel.setBackground(bg_color);
+	down_panel.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));
+
+        getContentPane().add(mid_panel, BorderLayout.NORTH);
+        getContentPane().add(browser_panel, BorderLayout.CENTER);
+	getContentPane().add(down_panel, BorderLayout.SOUTH);
+	getContentPane().setBackground(bg_color);
+	setVisible(true);
+    }
+
+    private class BrowseActionListener 
+ 	implements ActionListener {
+	
+	public void actionPerformed(ActionEvent ev) {
+	    JFileChooser chooser = new JFileChooser();
+           int returnVal = chooser.showOpenDialog(self);        
+	   
+	    if(returnVal == JFileChooser.APPROVE_OPTION) {
+                File program_path = chooser.getSelectedFile();
+		program_path_field.setText(program_path.getPath());
+	    } 
+	}
+
+     }
+
+    private class BrowserSelectionListener 
+ 	implements ActionListener {
+	
+	public void actionPerformed(ActionEvent ev) {
+	    if (default_browser_button.isSelected()){
+		program_path_field.setEnabled(false);
+                browse_button.setEnabled(false);
+	    }
+            else{
+		program_path_field.setEnabled(true);
+                browse_button.setEnabled(true);
+	    }
+	}
+
+     }
+    
+
+    private class SaveActionListener
+	implements ActionListener {
+	
+	public void actionPerformed(ActionEvent ev) {
+	    // save everything to build_properties if things have changed
+	     boolean has_changed = false;
+             boolean require_restart = false;
+	    if (portNum != ((Integer)portNumber_spinner.getValue()).intValue()) {
+		has_changed = true;
+                require_restart = true; 
+                server.reconfigRequired();
+                portNum = ((Integer)portNumber_spinner.getValue()).intValue();
+             	logger.info("port changed, new port is "+portNumber_spinner.getValue());
+	    }
+	    if (autoStart != autoEnter.isSelected()) {
+            	has_changed = true;
+	    }
+	    if (!servletDefault.equals(servlet_combobox.getSelectedItem())) {
+         	has_changed = true;
+                require_restart = true; 
+	    }
+            //changed to use other browser
+            if (useDefaultBrowser && other_browser_button.isSelected()){
+		browserPath = program_path_field.getText();
+		has_changed = true;
+	    } 
+	    //the browser path has been changed 
+	    if ( !useDefaultBrowser && !browserPath.equals(program_path_field.getText())){
+		browserPath = program_path_field.getText();
+		 has_changed = true;
+	    }
+	    
+            //changed to use the default browser
+	    if ( default_browser_button.isSelected() && !useDefaultBrowser){
+		browserPath = "";
+		has_changed = true;
+	    }
+             
+
+	    if (has_changed) {
+		ArrayList oldFileLines = null;
+		ArrayList newFileLines = null;
+		
+		ScriptReadWrite scriptReadWrite = new ScriptReadWrite();
+		oldFileLines = scriptReadWrite.readInFile(Server.build_properties_file);
+		
+		newFileLines = scriptReadWrite.queryReplace(oldFileLines, StaticStrings.TOMCAT_PORT_PROPERTY, portNum+"");
+		
+		String newAutoEnter = (new Boolean(autoEnter.isSelected())).toString();
+		newFileLines = scriptReadWrite.queryReplace(newFileLines, StaticStrings.AUTOSTART_PROPERTY, newAutoEnter);
+		
+		String newServletDef = (String) servlet_combobox.getSelectedItem();
+		newFileLines = scriptReadWrite.queryReplace(newFileLines,StaticStrings.DEFAULT_SERVLET_PROPERTY, (String) url_mappings.get(newServletDef));
+
+		String osName = System.getProperty("os.name");
+                if (osName.startsWith("Windows")){
+		    browserPath = browserPath.replaceAll("\\\\","/");
+		}
+                 newFileLines = scriptReadWrite.queryReplace(newFileLines,StaticStrings.BROWSER_PATH, browserPath);
+
+		scriptReadWrite.writeOutFile(Server.build_properties_file,
+					     newFileLines);
+		server.reloadBuildProperties();
+		if (require_restart){
+		    JOptionPane.showMessageDialog(null,server.dictionary.get("ServerSetting.SettingChanged"),"Info", JOptionPane.INFORMATION_MESSAGE);
+		}
+	    } 
+
+	    self.dispose();
+	}
+    }
+
+}
Index: /greenstone3/trunk/src/java/org/greenstone/server/StaticStrings.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/server/StaticStrings.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/server/StaticStrings.java	(revision 14125)
@@ -0,0 +1,19 @@
+package org.greenstone.server;
+
+public class StaticStrings {
+
+    static final public String GSDL3_HOME_PROPERTY = "gsdl3.home";
+    static final public String GSDL3_VERSION_PROPERTY = "gsdl3.version";
+    static final public String AUTOSTART_PROPERTY = "server.auto.start";
+    static final public String DEFAULT_SERVLET_PROPERTY = "server.default.servlet";
+    static final public String TOMCAT_SERVER_PROPERTY = "tomcat.server";
+    static final public String TOMCAT_PORT_PROPERTY = "tomcat.port";
+    static final public String TOMCAT_CONTEXT_PROPERTY = "tomcat.context";
+    static final public String TOMCAT_INSTALL_PATH = "tomcat.installed.path";
+
+    static final public String WIN_9X_OPEN_COMMAND = "command.com /c start %1";
+    static final public String WIN_OPEN_COMMAND = "cmd.exe /c start \"\" %1";
+    static final public String MAC_OPEN_COMMAND = "open %1";
+
+    static final public String BROWSER_PATH = "browser.path";
+}
Index: /greenstone3/trunk/src/java/org/greenstone/server/StreamGobbler.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/server/StreamGobbler.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/server/StreamGobbler.java	(revision 14125)
@@ -0,0 +1,39 @@
+package org.greenstone.server;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import org.apache.log4j.*;
+
+class StreamGobbler{
+    static Logger logger = Logger.getLogger(org.greenstone.server.StreamGobbler.class.getName());
+    
+    public static void logError(InputStream in)
+      {
+	  try {
+	      BufferedReader br = new BufferedReader(new InputStreamReader(in));
+	      String line = null;
+              //using null as a guard doesn't work on windows 
+  	      while ((line = br.readLine()) != null){
+		  logger.error(line);
+	      }
+	  } catch (IOException ioe) {
+	      logger.error(ioe);
+	  }
+      }
+    
+    
+    public void logInfo(InputStream in){
+	try {
+	    BufferedReader br = new BufferedReader(new InputStreamReader(in));
+	    String line = null;
+	    while ((line = br.readLine()) != null){
+		  logger.info(line);
+	      }
+	  } catch (IOException ioe) {
+	      logger.error(ioe);
+	  }
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/testing/ClassFinder.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/testing/ClassFinder.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/testing/ClassFinder.java	(revision 14125)
@@ -0,0 +1,83 @@
+/** this file originally downloaded from 
+ *http://www.javaworld.com/javaworld/jw-12-2000/junit/jw-1221-junit.zip
+ *
+ */
+
+package org.greenstone.testing;
+
+import java.util.*;
+import java.io.*;
+/*
+ * This used to use JCF. However, JCF seems to have dissapeared from the web.
+ * import lti.java.jcf.*;
+ */
+
+
+/**
+ * This class is responsible for searching a directory for class files. It builds
+ * a list of fully qualified class names from the class files in the directory tree.
+ */
+public class ClassFinder {
+    final private Vector classNameList = new Vector ();
+    final private int startPackageName;
+
+    /**
+     * Construct the class finder and locate all the classes in the directory structured
+     * pointed to by <code>classPathRoot</code>. Only classes in the package <code>packageRoot</code>
+     * are considered.
+     */
+    public ClassFinder(final File classPathRoot, final String packageRoot) throws IOException {
+        startPackageName = classPathRoot.getAbsolutePath().length() + 1;
+        String directoryOffset = packageRoot.replace ('.', File.separatorChar);
+        findAndStoreTestClasses (new File (classPathRoot, directoryOffset));
+    }
+    
+    /**
+     * Given a file name, guess the fully qualified class name.
+     */
+    private String computeClassName (final File file) {
+        String absPath = file.getAbsolutePath();
+        String packageBase = absPath.substring (startPackageName, absPath.length () - 6);
+        String className;
+        className = packageBase.replace(File.separatorChar, '.');
+        return className;
+    }
+
+    /**
+     * This method does all the work. It runs down the directory structure looking
+     * for java classes.
+     */
+    private void findAndStoreTestClasses (final File currentDirectory) throws IOException {
+        String files[] = currentDirectory.list();
+        for(int i = 0;i < files.length;i++) {
+            File file = new File(currentDirectory, files[i]);
+            String fileBase = file.getName ();
+            int idx = fileBase.indexOf(".class");
+            final int CLASS_EXTENSION_LENGTH = 6;
+            
+            if(idx != -1 && (fileBase.length() - idx) == CLASS_EXTENSION_LENGTH) {
+/* 
+ * This used to use JCF. However, JCF seems to have dissapeared from the web so we fallback
+ * to a less elegant method. We compute the class name from the file name :-(
+ *               JcfClassInputStream inputStream = new JcfClassInputStream(new FileInputStream (file));
+ *               JcfClassFile classFile = new JcfClassFile (inputStream);
+ *               System.out.println ("Processing: " + classFile.getFullName ().replace ('/','.'));
+ *               classNameList.add (classFile.getFullName ().replace ('/','.'));
+ */
+                String className = computeClassName (file);
+                classNameList.add (className);
+            } else {
+                if(file.isDirectory()) {
+                    findAndStoreTestClasses (file);
+                }
+            }
+        }
+    }
+
+    /**
+     * Return the found classes.
+     */
+    public Iterator getClasses () {
+        return classNameList.iterator ();
+    }
+}
Index: /greenstone3/trunk/src/java/org/greenstone/testing/TestCaseLoader.java
===================================================================
--- /greenstone3/trunk/src/java/org/greenstone/testing/TestCaseLoader.java	(revision 14125)
+++ /greenstone3/trunk/src/java/org/greenstone/testing/TestCaseLoader.java	(revision 14125)
@@ -0,0 +1,83 @@
+package org.greenstone.testing;
+import java.util.*;
+import java.lang.reflect.*;
+import junit.framework.*;
+/**
+ * Responsible for loading classes representing valid test cases.
+ */
+public class TestCaseLoader {
+    final private Vector classList = new Vector ();
+    final private String requiredType;
+    
+    /** 
+     * Adds <code>testCaseClass</code> to the list of classdes
+     * if the class is a test case we wish to load. Calls
+     * <code>shouldLoadTestCase ()</code> to determine that.
+     */
+    private void addClassIfTestCase (final Class testCaseClass) {
+        if (shouldAddTestCase (testCaseClass)) {
+            classList.add (testCaseClass);
+        }
+    }
+
+    /**
+     * Determine if we should load this test case. 
+     */
+    private boolean shouldAddTestCase (final Class testCaseClass) {
+        boolean isOfTheCorrectType = false;
+        if (TestCase.class.isAssignableFrom(testCaseClass)) {
+            try {
+                Field testAllIgnoreThisField = testCaseClass.getDeclaredField("TEST_ALL_TEST_TYPE");
+                final int EXPECTED_MODIFIERS = Modifier.STATIC | Modifier.PUBLIC | Modifier.FINAL;
+                if (((testAllIgnoreThisField.getModifiers() & EXPECTED_MODIFIERS) != EXPECTED_MODIFIERS) ||
+                    (testAllIgnoreThisField.getType() != String.class)) {
+                    throw new IllegalArgumentException ("TEST_ALL_TEST_TYPE should be static public final String");
+                }
+                String testType = (String)testAllIgnoreThisField.get(testCaseClass);
+                isOfTheCorrectType = requiredType.equals (testType);
+            } catch (NoSuchFieldException e) {
+            } catch (IllegalAccessException e) {
+                throw new IllegalArgumentException ("The field " + testCaseClass.getName () + ".TEST_ALL_TEST_TYPE is not accessible.");
+            }
+        }
+        return isOfTheCorrectType;
+    }
+    
+       
+    
+    /**
+     * Load the classes that represent test cases we are interested. 
+     * @param classNamesIterator An iterator over a collection of fully qualified class names
+     */
+    public void loadTestCases (final Iterator classNamesIterator) {
+        while (classNamesIterator.hasNext ()) {
+            String className = (String)classNamesIterator.next ();
+	    System.out.println("trying class "+className);
+            try {
+                Class candidateClass = Class.forName (className);
+                addClassIfTestCase (candidateClass);
+            } catch (ClassNotFoundException e) {
+                System.err.println ("Cannot load class: " + className + " " + e.getMessage ());
+            } catch (NoClassDefFoundError e) {
+                System.err.println ("Cannot load class that " + className + " is dependant on");
+            }
+        }
+    }
+        
+    /**
+     * Construct this instance. Load all the test cases possible that derive
+     * from <code>baseClass</code> and cannot be ignored. 
+     * @param classNamesIterator An iterator over a collection of fully qualified class names
+     */
+    public TestCaseLoader(final String requiredType) {
+        if (requiredType == null) throw new IllegalArgumentException ("requiredType is null");
+        this.requiredType = requiredType;
+    }
+    
+    /**
+     * Obtain an iterator over the collection of test case classes loaded by <code>loadTestCases</code>
+     */
+    public Iterator getClasses () {
+        return classList.iterator ();
+    }
+}
Index: /greenstone3/trunk/src/packages/javagdbm/CHANGES
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/CHANGES	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/CHANGES	(revision 14125)
@@ -0,0 +1,26 @@
+Release 0006 1998-03-06
+ - Added FAQ.html
+
+Release 0005 1997-10-30
+ - Deserializing objects from databases is implemented properly
+ - Added the Closeable interface
+ - Fixed link to home page in documentation
+
+Release 0004 1997-10-24
+ - Fixed bug in autoconfig script
+
+Release 0003 1997-10-24
+ - Release-management and CVS restructurings
+
+Release 0002 1997-10-23
+ - Much more developer documentation in javadoc format
+ - Support for Serialization and QuotedVector packing
+ - Packing objects now have consistent names
+ - New distribution page, separate from mbp's home page
+ - Moved all the code into packages which use the standard Java naming
+   conventions: au.com.pharos.gdbm
+
+Release 0001 1997-10-03
+ - Functional JNI-based interface
+ - Scanty documentation
+ - GPL release disclaimer from jdg
Index: /greenstone3/trunk/src/packages/javagdbm/FAQ.html
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/FAQ.html	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/FAQ.html	(revision 14125)
@@ -0,0 +1,173 @@
+<head><title>FAQ for JavaGDBM</title>
+</head>
+
+<h1>FAQ for JavaGDBM</h1>
+<p><pre>$Id$</pre>
+<p><a href="http://www.pharos.com.au/gdbm/"><b>Home page</b></a> |
+<a href="mailto:mbp@pharos.com.au"><b>mbp@pharos.com.au</b></a>
+
+<p><b>This is not an official publication of Pharos.  There is no
+warranty of any kind on this software or document.</b>
+
+<h3>Is this a JDBC driver?</h3>
+
+<p>(Alain Magloire)
+
+<p>No. JDBC seems mainly intended for interfaces to relational
+databases, and GDBM is not a relational database. 
+
+<p>However, JDBC does permit use of a subset to interface to
+non-relational databases.  Implementing this might be interesting: let
+me know if it's useful to you.
+
+<h3>Does JavaGDBM understand SQL?</h3>
+
+<p>(Alain Magloire)
+
+<p>No, JavaGDBM is intended to store on-disk hash tables.  They solve
+a different class of problem to that appropriate for SQL and
+relational databases.
+
+<h3>What type of database should I use?</h3>
+
+<p>Broadly, options for data storage in Java include
+
+<ul>
+<li>A hash file through JavaGDBM.
+<li>A relational database through JDBC
+<li>An object-oriented database
+<li>Serialization to a file
+</ul>
+
+<p>Make sure you choose the right tools: there is no single `best' answer.
+
+<h3>Are you maintaining GDBM?</h3>
+
+<p>No.  I understand that GDBM is still maintained by the FSF.
+
+<h3>Does it work on NT?</h3>
+
+<p>It should, but I haven't tried it.  You'll need a C compiler to
+build the native library.  Let me know if you try.
+
+<h3>Why does the test harness report exceptions</h3>
+
+<p>The test harness may report messages such as
+
+<pre>
+caught: au.com.pharos.gdbm.GdbmException: File open error: No such file or
+directory? (gdbmjava.c:101)
+</pre>
+
+<p>These are expected exceptions: the test harness is making sure that
+exceptions are thrown when they should be.
+
+<h3>I was trying to compile the Java GDBM distribution and it says gdbm.h not found</h3>
+
+<p>(Sandeep Kumar)
+
+<ol>
+<li>Make sure you have the GDBM library installed on your system.  
+If the library is not installed, you should be able to find it at 
+<a href="http://www.gnu.org/">www.gnu.org</a>
+
+<li>Make sure your compiler is configured to find the libraries and
+include files.
+
+</ol>
+
+<h3><tt>GdbmFile.h</tt> is missing</h3>
+
+<p>(Paul Matthews)
+
+<p><tt>GdbmFile.h</tt> is build by <tt>javah</tt> when the library is
+built.
+
+<h3>What is the best source to learn Java?</h3>
+
+<p>(Celil Germeyan)
+
+<p>Personally, I recommend the excellent Java series of books from
+<a href="http://www.ora.com/info/java/bibliography.html/">O'Reilly and
+Associates</a> and the
+<a href="http://java.sun.com/docs/books/index.html">Javasoft/Addison
+Wesley</a> books.
+
+<h3>I get a `not ok 40' message running the test</h3>
+
+<p>(Steve Waldman)
+
+<p>If you find a bug, either have a look at the code yourself, or
+send e-mail to 
+<a href="mailto:mbp@pharos.com.au"><tt>mbp@pharos.com.au</tt></a>.  
+There's no warranty on JavaGDBM, but I will try to respond to your
+mail and problem.
+
+<h3>I get linker errors on Solaris</h3>
+
+<p>(Alex Soto)
+
+<pre>
+Hi,
+
+    I'm hoping to use your JavaGDBM api for my application, but I'm
+having some problems compiling the libgdbmjava.so.  Here is a partial
+listing of the errors:
+
+gcc -o libgdbmjava.so -shared gdbmjava.o -lgdbm
+Text relocation remains                       referenced
+    against symbol                  offset      in file
+free                                0x258
+/usr/local/lib/libgdbm.a(gdbmreorg.o)
+free                                0xd0
+/usr/local/lib/libgdbm.a(gdbmclose.o)
+free                                0xb8
+/usr/local/lib/libgdbm.a(gdbmclose.o)
+free                                0x218
+[snipped]
+
+I have used the libgdbm.a lib before, and don't believe there is a
+problem with it.  I'm compiling to Solaris 2.6, using JDK 1.1.4.
+</pre>
+
+<p>The solution turned out to be that the gdbm native library
+must be compiled with the <tt>-fpic</tt> flag to cause the compiler to
+generate position-independant code.  
+
+<h3>What happens if a reader tries to open the database while a writer is doing something?</h3>
+
+<p>(Rich Neill)
+
+<p>Access will be denied until the writer releases its lock.  
+
+<p>JavaGDBM uses a shared-read/exclusive-write protocol at the OS
+level.  However, multiple Java threads can access a file concurrently.
+
+<h3>What platforms does JavaGDBM run on?</H3>
+
+<p>It should run on any platform that supports JDK1.1 or higher, JNI
+(Java Native Interface), and GDBM.  JavaGDBM is known to run on 
+
+<ul>
+<li>Linux/i386
+<li>Solaris/SPARC and Solaris/i86
+<li>AIX 4
+</ul>
+
+<p>If you have any information on other platforms, please let me know.
+
+<h3>You don't anticipate going Pure Java soon, do you?</h3>
+
+<p>(Brian Thorstad)
+
+<p>It's on the `long-term' TODO list.  I'd like to do it, but don't have
+any date in mind.
+
+<h3>Acknowledgements</h3>
+
+<p>Everybody who's sent in questions or comments.
+
+<p>Redhat and Javasoft, and the authors of GDBM, Linux, gcc, autoconf,
+and other software used in building JavaGDBM.
+
+</html>
Index: /greenstone3/trunk/src/packages/javagdbm/LICENSE
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/LICENSE	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/LICENSE	(revision 14125)
@@ -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: /greenstone3/trunk/src/packages/javagdbm/Makefile.in
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/Makefile.in	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/Makefile.in	(revision 14125)
@@ -0,0 +1,25 @@
+# Main Makefile for Java GDBM
+# Katherine Don
+
+SUBDIRS = java jni
+MDEFINES = 
+
+all install clean:
+	for subdir in $(SUBDIRS); do \
+	echo making $@ in $$subdir; \
+	(cd $$subdir && $(MAKE) $(MDEFINES) $@) || exit 1; \
+	done
+
+javaonly:
+	cd java && $(MAKE) $(MDEFINES) all
+
+installjava:
+	cd java && $(MAKE) $(MDEFINES) install
+
+distclean: 
+	rm -f Makefile config.cache config.log config.status ;\
+	for subdir in $(SUBDIRS); do \
+	echo making $@ in $$subdir; \
+	(cd $$subdir && $(MAKE) $(MDEFINES) $@) || exit 1; \
+	done	
+
Index: /greenstone3/trunk/src/packages/javagdbm/README.txt
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/README.txt	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/README.txt	(revision 14125)
@@ -0,0 +1,31 @@
+A Java Interface to GDBM
+
+*****
+This is a most of the Java gdbm download. I have left out some unnecessary bits for the greenstone version. The original home page for this is no longer available, but http://aurora.regenstrief.org/~schadow/dbm-java/ has links to the original tar file.
+I have also updated the Makefiles so that it works on Windows and MacOSX.
+[kjdon, 2005]
+*****
+
+Martin Pool <m.pool@pharos.com.au>  1998-03-12
+
+ This is a Java interface to the GDBM database library written by Philip A Nelson. Like GDBM itself, this interface is free software, and comes with no warranty of any kind.
+
+GDBM is a library of database functions for implementing a hash on disk. JavaGDBM is an API for the Java programmer, not an applet or database package for end users.
+
+In Java terms, a GdbmFile is very similar to a java.util.Dictionary object, except that objects are reliably written to and retrieved from disk. An adaptor class, GdbmDictionary, presents that interface to maintain compatibility with existing code.
+
+GDBM enforces file and object locking to allow databases to be safely shared between multiple threads or processes. A database may be open read-write by one process, or read-only by any number of processes. Within each process, any number of threads may share the database. Within the limits of the operating system and hardware, GDBM will ensure that changes are atomically committed to disk, making the database safe even if the program terminates abnormally.
+
+JavaGDBM stores key/data pairs in a GdbmFile object, which represents a single disk file. Each key must be unique, and is paired with a single data item. The keys are not ordered: if you want to retrieve the objects in sorted order you can build an external index. The basic operations on
+
+As for a Dictionary, the basic operations that may be performed on a GdbmFile are to fetch, test for existence, store and delete records.
+
+Since Java objects are dynamically typed and GDBM data are typeless, JavaGDBM uses Strategy objects to allow objects to be encoded and decoded in various ways. Classes derived from the abstract Packing class may pack ojbects for storage as byte arrays, Unicode or ASCII strings, as serialized Java objects, or in a user-defined fashion. The packing strategy is defined at runtime for both the key and value of the records.
+
+Some example code is available in the test harness GdbmTest.java.
+
+The current implementation of JavaGDBM uses native glue code to link to the GDBM library via JNI, the Java Native Interface. This means that you must have a C compiler, the GDBM library, and related tools to compile the native portions JavaGDBM also requires a JDK1.1-compatible Java compiler, libraries, and runtime.
+
+If the GDBM libraries didn't come with your system, then you can download the GDBM source and install it.
+
+GDBM is known to work on Linux, NetBSD, Solaris, and AIX. 
Index: /greenstone3/trunk/src/packages/javagdbm/TODO
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/TODO	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/TODO	(revision 14125)
@@ -0,0 +1,21 @@
+TODO for JavaGDBM
+$Id$
+
+Short-term
+
+ - Fix reported bugs
+
+Medium-term
+
+ - Modify the Makefile and configuration code to make sure JavaGDBM
+   builds on more different systems.
+
+ - Add support for non-default block sizes and other options.
+
+ - Offer more developer documentation.
+
+Long-term
+
+ - Rewrite the native code in Java to make the system 100% Pure.
+ - Offer precompiled binaries(?)
+
Index: /greenstone3/trunk/src/packages/javagdbm/configure
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/configure	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/configure	(revision 14125)
@@ -0,0 +1,5337 @@
+#! /bin/sh
+# From configure.in Revision: 1.3 .
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.59.
+#
+# Copyright (C) 2003 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+  set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)$' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+  	  /^X\/\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\/\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x$as_lineno_3"  = "x$as_lineno_2"  || {
+  # Find who we are.  Look in the path if we contain no path at all
+  # relative or not.
+  case $0 in
+    *[\\/]* ) as_myself=$0 ;;
+    *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+       ;;
+  esac
+  # We did not find ourselves, most probably we were run as `sh COMMAND'
+  # in which case we are not to be found in the path.
+  if test "x$as_myself" = x; then
+    as_myself=$0
+  fi
+  if test ! -f "$as_myself"; then
+    { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2
+   { (exit 1); exit 1; }; }
+  fi
+  case $CONFIG_SHELL in
+  '')
+    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for as_base in sh bash ksh sh5; do
+	 case $as_dir in
+	 /*)
+	   if ("$as_dir/$as_base" -c '
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x$as_lineno_3"  = "x$as_lineno_2" ') 2>/dev/null; then
+	     $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+	     $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+	     CONFIG_SHELL=$as_dir/$as_base
+	     export CONFIG_SHELL
+	     exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+	   fi;;
+	 esac
+       done
+done
+;;
+  esac
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line before each line; the second 'sed' does the real
+  # work.  The second script uses 'N' to pair each line-number line
+  # with the numbered line, and appends trailing '-' during
+  # substitution so that $LINENO is not a special case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # second 'sed' script.  Blame Lee E. McMahon for sed's syntax.  :-)
+  sed '=' <$as_myself |
+    sed '
+      N
+      s,$,-,
+      : loop
+      s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+      t loop
+      s,-$,,
+      s,^['$as_cr_digits']*\n,,
+    ' >$as_me.lineno &&
+  chmod +x $as_me.lineno ||
+    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensible to this).
+  . ./$as_me.lineno
+  # Exit status is that of the last command.
+  exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+  *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T='	' ;;
+  *c*,*  ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+  *)       ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  # We could just check for DJGPP; but this test a) works b) is more generic
+  # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+  if test -f conf$$.exe; then
+    # Don't use ln at all; we don't have any links
+    as_ln_s='cp -p'
+  else
+    as_ln_s='ln -s'
+  fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" 	$as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+exec 6>&1
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_config_libobj_dir=.
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete.  It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+ac_unique_file="jni/gdbmjava.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S CPP EGREP JAVA_HOME javagdbm_cv_path_javah javagdbm_cv_path_java GDBM_LIBPATH GDBM_INCLUDE PKG JNIINC JNISUFFIX JNIFLAGS LIBOBJS LTLIBOBJS'
+ac_subst_files=''
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+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'
+
+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
+
+  ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+  # 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_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$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 ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+    eval "enable_$ac_feature=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+    case $ac_option in
+      *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+      *) 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 | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$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 | -n)
+    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_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case $ac_option in
+      *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_$ac_package='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    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 "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; }
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+   { (exit 1); exit 1; }; }
+    ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+    eval "$ac_envvar='$ac_optarg'"
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  { echo "$as_me: error: missing argument to $ac_option" >&2
+   { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+  eval ac_val=$`echo $ac_var`
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+    *)  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+	      localstatedir libdir includedir oldincludedir infodir mandir
+do
+  eval ac_val=$`echo $ac_var`
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* ) ;;
+    *)  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+    echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used." >&2
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+# 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_confdir=`(dirname "$0") 2>/dev/null ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$0" : 'X\(//\)[^/]' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X"$0" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+  	  /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+  	  /^X\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+  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 "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
+   { (exit 1); exit 1; }; }
+  else
+    { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+   { (exit 1); exit 1; }; }
+  fi
+fi
+(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+  { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
+   { (exit 1); exit 1; }; }
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+ac_env_CPP_set=${CPP+set}
+ac_env_CPP_value=$CPP
+ac_cv_env_CPP_set=${CPP+set}
+ac_cv_env_CPP_value=$CPP
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # 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 <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+_ACEOF
+
+  cat <<_ACEOF
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+			  [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+			  [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR           user executables [EPREFIX/bin]
+  --sbindir=DIR          system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR       program executables [EPREFIX/libexec]
+  --datadir=DIR          read-only architecture-independent data [PREFIX/share]
+  --sysconfdir=DIR       read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR   modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR    modifiable single-machine data [PREFIX/var]
+  --libdir=DIR           object code libraries [EPREFIX/lib]
+  --includedir=DIR       C header files [PREFIX/include]
+  --oldincludedir=DIR    C header files for non-gcc [/usr/include]
+  --infodir=DIR          info documentation [PREFIX/info]
+  --mandir=DIR           man documentation [PREFIX/man]
+_ACEOF
+
+  cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+  cat <<\_ACEOF
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-gdbm=dir         Use local gdbm library and headers
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  CPPFLAGS    C/C++ preprocessor flags, e.g. -I<include dir> if you have
+              headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_ACEOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  ac_popdir=`pwd`
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d $ac_dir || continue
+    ac_builddir=.
+
+if test "$ac_dir" != .; then
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A "../" for each directory in $ac_dir_suffix.
+  ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+  ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+  .)  # No --srcdir option.  We are building in place.
+    ac_srcdir=.
+    if test -z "$ac_top_builddir"; then
+       ac_top_srcdir=.
+    else
+       ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+    fi ;;
+  [\\/]* | ?:[\\/]* )  # Absolute path.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir ;;
+  *) # Relative path.
+    ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+  case "$ac_dir" in
+  .) ac_abs_builddir=`pwd`;;
+  [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+  *) ac_abs_builddir=`pwd`/"$ac_dir";;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+  case ${ac_top_builddir}. in
+  .) ac_abs_top_builddir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+  *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+  case $ac_srcdir in
+  .) ac_abs_srcdir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+  *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+  case $ac_top_srcdir in
+  .) ac_abs_top_srcdir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+  *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+  esac;;
+esac
+
+    cd $ac_dir
+    # Check for guested configure; otherwise get Cygnus style configure.
+    if test -f $ac_srcdir/configure.gnu; then
+      echo
+      $SHELL $ac_srcdir/configure.gnu  --help=recursive
+    elif test -f $ac_srcdir/configure; then
+      echo
+      $SHELL $ac_srcdir/configure  --help=recursive
+    elif test -f $ac_srcdir/configure.ac ||
+	   test -f $ac_srcdir/configure.in; then
+      echo
+      $ac_configure --help
+    else
+      echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi
+    cd $ac_popdir
+  done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+  cat <<\_ACEOF
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit 0
+fi
+exec 5>config.log
+cat >&5 <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.59.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+hostinfo               = `(hostinfo) 2>/dev/null               || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  echo "PATH: $as_dir"
+done
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_sep=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+      ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+    2)
+      ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+	ac_must_keep_next=false # Got value, back to normal.
+      else
+	case $ac_arg in
+	  *=* | --config-cache | -C | -disable-* | --disable-* \
+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+	  | -with-* | --with-* | -without-* | --without-* | --x)
+	    case "$ac_configure_args0 " in
+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+	    esac
+	    ;;
+	  -* ) ac_must_keep_next=true ;;
+	esac
+      fi
+      ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+      # Get rid of the leading space.
+      ac_sep=" "
+      ;;
+    esac
+  done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Be sure not to use single quotes in there, as some shells,
+# such as our DU 5.0 friend, will then `close' the trap.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+{
+  (set) 2>&1 |
+    case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+    *ac_space=\ *)
+      sed -n \
+	"s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+      ;;
+    *)
+      sed -n \
+	"s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+      ;;
+    esac;
+}
+    echo
+
+    cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=$`echo $ac_var`
+      echo "$ac_var='"'"'$ac_val'"'"'"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      cat <<\_ASBOX
+## ------------- ##
+## Output files. ##
+## ------------- ##
+_ASBOX
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=$`echo $ac_var`
+	echo "$ac_var='"'"'$ac_val'"'"'"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+      echo
+      sed "/^$/d" confdefs.h | sort
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      echo "$as_me: caught signal $ac_signal"
+    echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core &&
+  rm -rf conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+     ' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# 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
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# 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 "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special
+  # files actually), so we avoid doing that.
+  if test -f "$cache_file"; then
+    { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . $cache_file;;
+      *)                      . ./$cache_file;;
+    esac
+  fi
+else
+  { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in `(set) 2>&1 |
+	       sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val="\$ac_cv_env_${ac_var}_value"
+  eval ac_new_val="\$ac_env_${ac_var}_value"
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+	{ echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	{ echo "$as_me:$LINENO:   former value:  $ac_old_val" >&5
+echo "$as_me:   former value:  $ac_old_val" >&2;}
+	{ echo "$as_me:$LINENO:   current value: $ac_new_val" >&5
+echo "$as_me:   current value: $ac_new_val" >&2;}
+	ac_cache_corrupted=:
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+      ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-gdbm or --without-gdbm was given.
+if test "${with_gdbm+set}" = set; then
+  withval="$with_gdbm"
+  gdbmdir=$withval
+fi;
+
+# TODO: allow the user to specify whether they want a debugging
+# library or not?
+
+# check for compilers and other tools
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  CC=$ac_ct_CC
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  CC=$ac_ct_CC
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+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 "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+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 $# != 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
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in 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 "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  test -n "$ac_ct_CC" && break
+done
+
+  CC=$ac_ct_CC
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+     "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+  (eval $ac_compiler --version </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+  (eval $ac_compiler -v </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+  (eval $ac_compiler -V </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5
+  (eval $ac_link_default) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # Find the output, starting from the most likely.  This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+
+# Be careful to initialize this variable, since it used to be cached.
+# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile.
+ac_cv_exeext=
+# b.out is created by i960 compilers.
+for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj )
+	;;
+    conftest.$ac_ext )
+	# This is the source file.
+	;;
+    [ab].out )
+	# We found the default executable, but exeext='' is most
+	# certainly right.
+	break;;
+    *.* )
+	ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	# FIXME: I believe we export ac_cv_exeext for Libtool,
+	# but it would be cool to find out if it's true.  Does anybody
+	# maintain Libtool? --akim.
+	export ac_cv_exeext
+	break;;
+    * )
+	break;;
+  esac
+done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+  if { ac_try='./$ac_file'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+  fi
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	  export ac_cv_exeext
+	  break;;
+    * ) break;;
+  esac
+done
+else
+  { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_compiler_gnu=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&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 "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std1 is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std1.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+# 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 10.20 and later	-Ae
+# HP-UX older versions	-Aa -D_HPUX_SOURCE
+# SVR4			-Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+case "x$ac_cv_prog_cc_stdc" in
+  x|xno)
+    echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+  *)
+    echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+    CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+# Some people use a C++ compiler to compile C.  Since we use `exit',
+# in C++ we need to declare it.  In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+  choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  for ac_declaration in \
+   '' \
+   'extern "C" void std::exit (int) throw (); using std::exit;' \
+   'extern "C" void std::exit (int); using std::exit;' \
+   'extern "C" void exit (int) throw ();' \
+   'extern "C" void exit (int);' \
+   'void exit (int);'
+do
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_declaration
+#include <stdlib.h>
+int
+main ()
+{
+exit (42);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+  echo '#ifdef __cplusplus' >>confdefs.h
+  echo $ac_declaration      >>confdefs.h
+  echo '#endif'             >>confdefs.h
+fi
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+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
+  elif test -f $ac_dir/shtool; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5
+echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $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
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# 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"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+  ./ | .// | /cC/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+  /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
+      for ac_exec_ext in '' $ac_executable_extensions; do
+	if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+	  if test $ac_prog = install &&
+	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+	    break 3
+	  fi
+	fi
+      done
+    done
+    ;;
+esac
+done
+
+
+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 "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&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}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo "$as_me:$LINENO: checking whether ln -s works" >&5
+echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+  echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+  echo "$as_me:$LINENO: result: no, using $LN_S" >&5
+echo "${ECHO_T}no, using $LN_S" >&6
+fi
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if test "${ac_cv_prog_CPP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether non-existent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether non-existent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  :
+else
+  { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6
+if test "${ac_cv_prog_egrep+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+    then ac_cv_prog_egrep='grep -E'
+    else ac_cv_prog_egrep='egrep'
+    fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5
+echo "${ECHO_T}$ac_cv_prog_egrep" >&6
+ EGREP=$ac_cv_prog_egrep
+
+
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_header_stdc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then
+  :
+else
+  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 <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then
+  :
+else
+  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 <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#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);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+		  inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  eval "$as_ac_Header=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+echo "$as_me:$LINENO: checking for void *" >&5
+echo $ECHO_N "checking for void *... $ECHO_C" >&6
+if test "${ac_cv_type_void_p+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+if ((void * *) 0)
+  return 0;
+if (sizeof (void *))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_type_void_p=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_void_p=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_void_p" >&5
+echo "${ECHO_T}$ac_cv_type_void_p" >&6
+
+echo "$as_me:$LINENO: checking size of void *" >&5
+echo $ECHO_N "checking size of void *... $ECHO_C" >&6
+if test "${ac_cv_sizeof_void_p+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$ac_cv_type_void_p" = yes; then
+  # The cast to unsigned long works around a bug in the HP C Compiler
+  # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+  # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+  # This bug is HP SR number 8606223364.
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (void *))) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (void *))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+		    if test $ac_lo -le $ac_mid; then
+		      ac_lo= ac_hi=
+		      break
+		    fi
+		    ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (void *))) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (void *))) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+		       if test $ac_mid -le $ac_hi; then
+			 ac_lo= ac_hi=
+			 break
+		       fi
+		       ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (void *))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_void_p=$ac_lo;;
+'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (void *), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (void *), 77
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; } ;;
+esac
+else
+  if test "$cross_compiling" = yes; then
+  { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+long longval () { return (long) (sizeof (void *)); }
+unsigned long ulongval () { return (long) (sizeof (void *)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    exit (1);
+  if (((long) (sizeof (void *))) < 0)
+    {
+      long i = longval ();
+      if (i != ((long) (sizeof (void *))))
+	exit (1);
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long i = ulongval ();
+      if (i != ((long) (sizeof (void *))))
+	exit (1);
+      fprintf (f, "%lu\n", i);
+    }
+  exit (ferror (f) || fclose (f) != 0);
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_void_p=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+{ { echo "$as_me:$LINENO: error: cannot compute sizeof (void *), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (void *), 77
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+else
+  ac_cv_sizeof_void_p=0
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sizeof_void_p" >&5
+echo "${ECHO_T}$ac_cv_sizeof_void_p" >&6
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_VOID_P $ac_cv_sizeof_void_p
+_ACEOF
+
+
+echo "$as_me:$LINENO: checking for int" >&5
+echo $ECHO_N "checking for int... $ECHO_C" >&6
+if test "${ac_cv_type_int+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+if ((int *) 0)
+  return 0;
+if (sizeof (int))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_type_int=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_int=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_int" >&5
+echo "${ECHO_T}$ac_cv_type_int" >&6
+
+echo "$as_me:$LINENO: checking size of int" >&5
+echo $ECHO_N "checking size of int... $ECHO_C" >&6
+if test "${ac_cv_sizeof_int+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$ac_cv_type_int" = yes; then
+  # The cast to unsigned long works around a bug in the HP C Compiler
+  # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+  # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+  # This bug is HP SR number 8606223364.
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (int))) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (int))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+		    if test $ac_lo -le $ac_mid; then
+		      ac_lo= ac_hi=
+		      break
+		    fi
+		    ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (int))) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (int))) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+		       if test $ac_mid -le $ac_hi; then
+			 ac_lo= ac_hi=
+			 break
+		       fi
+		       ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (int))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_int=$ac_lo;;
+'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (int), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (int), 77
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; } ;;
+esac
+else
+  if test "$cross_compiling" = yes; then
+  { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+long longval () { return (long) (sizeof (int)); }
+unsigned long ulongval () { return (long) (sizeof (int)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    exit (1);
+  if (((long) (sizeof (int))) < 0)
+    {
+      long i = longval ();
+      if (i != ((long) (sizeof (int))))
+	exit (1);
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long i = ulongval ();
+      if (i != ((long) (sizeof (int))))
+	exit (1);
+      fprintf (f, "%lu\n", i);
+    }
+  exit (ferror (f) || fclose (f) != 0);
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_int=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+{ { echo "$as_me:$LINENO: error: cannot compute sizeof (int), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (int), 77
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+else
+  ac_cv_sizeof_int=0
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sizeof_int" >&5
+echo "${ECHO_T}$ac_cv_sizeof_int" >&6
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_INT $ac_cv_sizeof_int
+_ACEOF
+
+
+echo "$as_me:$LINENO: checking for long" >&5
+echo $ECHO_N "checking for long... $ECHO_C" >&6
+if test "${ac_cv_type_long+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+if ((long *) 0)
+  return 0;
+if (sizeof (long))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_type_long=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_long=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_long" >&5
+echo "${ECHO_T}$ac_cv_type_long" >&6
+
+echo "$as_me:$LINENO: checking size of long" >&5
+echo $ECHO_N "checking size of long... $ECHO_C" >&6
+if test "${ac_cv_sizeof_long+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$ac_cv_type_long" = yes; then
+  # The cast to unsigned long works around a bug in the HP C Compiler
+  # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+  # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+  # This bug is HP SR number 8606223364.
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long))) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr $ac_mid + 1`
+		    if test $ac_lo -le $ac_mid; then
+		      ac_lo= ac_hi=
+		      break
+		    fi
+		    ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long))) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long))) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_hi=`expr '(' $ac_mid ')' - 1`
+		       if test $ac_mid -le $ac_hi; then
+			 ac_lo= ac_hi=
+			 break
+		       fi
+		       ac_mid=`expr 2 '*' $ac_mid`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo= ac_hi=
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long) (sizeof (long))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_long=$ac_lo;;
+'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (long), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long), 77
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; } ;;
+esac
+else
+  if test "$cross_compiling" = yes; then
+  { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+long longval () { return (long) (sizeof (long)); }
+unsigned long ulongval () { return (long) (sizeof (long)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    exit (1);
+  if (((long) (sizeof (long))) < 0)
+    {
+      long i = longval ();
+      if (i != ((long) (sizeof (long))))
+	exit (1);
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long i = ulongval ();
+      if (i != ((long) (sizeof (long))))
+	exit (1);
+      fprintf (f, "%lu\n", i);
+    }
+  exit (ferror (f) || fclose (f) != 0);
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_long=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+{ { echo "$as_me:$LINENO: error: cannot compute sizeof (long), 77
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long), 77
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.val
+else
+  ac_cv_sizeof_long=0
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_sizeof_long" >&5
+echo "${ECHO_T}$ac_cv_sizeof_long" >&6
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_LONG $ac_cv_sizeof_long
+_ACEOF
+
+
+
+######## check for the JDK and tools within the JDK
+######## look in the JAVA_HOME environment variable at configure-time
+echo "$as_me:$LINENO: checking for the JDK" >&5
+echo $ECHO_N "checking for the JDK... $ECHO_C" >&6
+if test "z$JAVA_HOME" != z &&
+   test -d $JAVA_HOME &&
+   test -d $JAVA_HOME/include
+then
+
+	echo "$as_me:$LINENO: result: found in $JAVA_HOME" >&5
+echo "${ECHO_T}found in $JAVA_HOME" >&6
+else
+	{ { echo "$as_me:$LINENO: error: not found in \$JAVA_HOME" >&5
+echo "$as_me: error: not found in \$JAVA_HOME" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+# TODO: Check for specific header files in the JDK, or
+# functions/definitions within those headers?
+
+# TODO: guess which include directory to use under the JDK
+
+# Extract the first word of "javah", so it can be a program name with args.
+set dummy javah; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_javagdbm_cv_path_javah+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $javagdbm_cv_path_javah in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_javagdbm_cv_path_javah="$javagdbm_cv_path_javah" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_javagdbm_cv_path_javah="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_path_javagdbm_cv_path_javah" && ac_cv_path_javagdbm_cv_path_javah="missing_javah"
+  ;;
+esac
+fi
+javagdbm_cv_path_javah=$ac_cv_path_javagdbm_cv_path_javah
+
+if test -n "$javagdbm_cv_path_javah"; then
+  echo "$as_me:$LINENO: result: $javagdbm_cv_path_javah" >&5
+echo "${ECHO_T}$javagdbm_cv_path_javah" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+if test "$javagdbm_cv_path_javah" = missing_javah; then
+	{ { echo "$as_me:$LINENO: error: javah not found." >&5
+echo "$as_me: error: javah not found." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+# Extract the first word of "java", so it can be a program name with args.
+set dummy java; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_javagdbm_cv_path_java+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $javagdbm_cv_path_java in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_javagdbm_cv_path_java="$javagdbm_cv_path_java" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_javagdbm_cv_path_java="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_path_javagdbm_cv_path_java" && ac_cv_path_javagdbm_cv_path_java="missing"
+  ;;
+esac
+fi
+javagdbm_cv_path_java=$ac_cv_path_javagdbm_cv_path_java
+
+if test -n "$javagdbm_cv_path_java"; then
+  echo "$as_me:$LINENO: result: $javagdbm_cv_path_java" >&5
+echo "${ECHO_T}$javagdbm_cv_path_java" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+if test "$javagdbm_cv_path_java" = missing; then
+	{ { echo "$as_me:$LINENO: error: java not found." >&5
+echo "$as_me: error: java not found." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+# check for gdbm library
+#AC_CHECK_LIB(gdbm, gdbm_open, [javagdbm_cv_lib_gdbm="-lgdbm"],
+#	[javagdbm_cv_lib_gdbm=no])
+#if test "$javagdbm_cv_lib_gdbm" = "no"; then
+#	AC_MSG_ERROR([no native gdbm library found.])
+#fi
+#LIBS="$javagdbm_cv_lib_gdbm"
+
+# gdbm stuff copied from gsdl [kjdon]
+
+
+echo "$as_me:$LINENO: checking that the GDBM library is available" >&5
+echo $ECHO_N "checking that the GDBM library is available... $ECHO_C" >&6
+if test ! -z "$gdbmdir" ; then
+  # look in given directory for header file
+  if test -r $gdbmdir/include/gdbm.h ; then
+    GDBM_INCLUDE="-I$gdbmdir/include" ;
+  elif test -r $gdbmdir/gdbm.h ; then
+    GDBM_INCLUDE="-I$gdbmdir" ;
+  fi
+
+  # look in given directory for library
+  if test -r $gdbmdir/libgdbm.a ; then
+    GDBM_LIBPATH="-L$gdbmdir" ;
+  elif test -r $gdbmdir/lib/libgdbm.a ; then
+    GDBM_LIBPATH="-L$gdbmdir/lib" ;
+  elif test -r $gdbmdir/.libs/libgdbm.a ; then
+    GDBM_LIBPATH="-L$gdbmdir/.libs" ;
+  fi
+
+  if test ! -z "$GDBM_LIBPATH" -a ! -z "$GDBM_INCLUDE" ; then
+    echo "$as_me:$LINENO: result: $gdbmdir" >&5
+echo "${ECHO_T}$gdbmdir" >&6 ;
+  else
+    echo "$as_me:$LINENO: result: can't find gdbm.h and libgdbm.a in $gdbmdir" >&5
+echo "${ECHO_T}can't find gdbm.h and libgdbm.a in $gdbmdir" >&6;
+    echo "$as_me:$LINENO: checking looking for GDBM library in default locations" >&5
+echo $ECHO_N "checking looking for GDBM library in default locations... $ECHO_C" >&6
+  fi
+fi
+
+# look in default path and in /usr/local
+if test -z "$GDBM_INCLUDE" ; then
+  # try in system directory
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <gdbm.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  success=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+success=no
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+  if test $success = "no"; then
+# last chance - look in /usr/local (eg FreeBSD)
+    GDBM_LIBPATH=-L/usr/local/lib
+    GDBM_INCLUDE=-I/usr/local/include
+    ac_save_CXXFLAGS="$CXXFLAGS"
+    ac_save_LIBS="$LIBS"
+      CXXFLAGS="$CXXFLAGS -I/usr/local/include"
+      LIBS="$LIBS -L/usr/local/lib -lgdbm"
+      cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <gdbm.h>
+#include <stdio.h>
+
+int
+main ()
+{
+printf("%s",gdbm_version);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  success=/usr/local
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+success=no
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+      CXXFLAGS=$ac_save_CXXFLAGS
+      LIBS=$ac_save_LIBS
+  fi
+
+  echo "$as_me:$LINENO: result: $success" >&5
+echo "${ECHO_T}$success" >&6
+  if test $success = "no"; then
+  { { echo "$as_me:$LINENO: error: GDBM Library not available - cannot install" >&5
+echo "$as_me: error: GDBM Library not available - cannot install" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+fi
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LIBGDBM  1
+_ACEOF
+
+
+
+
+
+########## set compiler options
+# TODO: is there a more appropriate way to guess which switches to use
+# with which systems/compilers?
+CFLAGS="-Wall -O2 -fpic"
+PKG="au.com.pharos.gdbm"
+
+
+
+
+# we need to set an extended JNI path for Mac OS/Darwin, as jni.h is on
+# a non-standard Path
+# is there a better way to do this??
+echo "$as_me:$LINENO: checking for OS to set JNI options" >&5
+echo $ECHO_N "checking for OS to set JNI options... $ECHO_C" >&6
+# set defaults
+JNIINC=""
+JNISUFFIX="so"
+JNIFLAGS="-shared"
+
+if test "`(uname -s) 2> /dev/null`" = 'Darwin'; then
+  echo "$as_me:$LINENO: result: Darwin" >&5
+echo "${ECHO_T}Darwin" >&6
+  JNIINC="-I/System/Library/Frameworks/JavaVM.framework/Headers/ "
+  JNISUFFIX="jnilib"
+  JNIFLAGS="-dynamiclib -fno-common -single_module -framework JavaVM"
+fi
+if test "`(uname -s) 2> /dev/null`" = 'SunOS'; then
+  echo "$as_me:$LINENO: result: Solaris" >&5
+echo "${ECHO_T}Solaris" >&6
+  JNIINC="-I\$(JAVA_HOME)/include/solaris "
+fi
+if test "`(uname -s) 2> /dev/null`" = 'Linux'; then
+  echo "$as_me:$LINENO: result: Linux" >&5
+echo "${ECHO_T}Linux" >&6
+  JNIINC="-I\$(JAVA_HOME)/include/linux "
+fi
+
+
+
+
+
+# write the output
+                              ac_config_files="$ac_config_files Makefile jni/Makefile java/Makefile"
+cat >confcache <<\_ACEOF
+# 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, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# 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 \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;;
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n \
+	"s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+      ;;
+    esac;
+} |
+  sed '
+     t clear
+     : clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     : end' >>confcache
+if diff $cache_file confcache >/dev/null 2>&1; then :; else
+  if test -w $cache_file; then
+    test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
+    cat confcache >$cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[	 ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[	 ]*$//;
+}'
+fi
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then we branch to the quote section.  Otherwise,
+# look for a macro that doesn't take arguments.
+cat >confdef2opt.sed <<\_ACEOF
+t clear
+: clear
+s,^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 (][^	 (]*([^)]*)\)[	 ]*\(.*\),-D\1=\2,g
+t quote
+s,^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 ][^	 ]*\)[	 ]*\(.*\),-D\1=\2,g
+t quote
+d
+: quote
+s,[	 `~#$^&*(){}\\|;'"<>?],\\&,g
+s,\[,\\&,g
+s,\],\\&,g
+s,\$,$$,g
+p
+_ACEOF
+# We use echo to avoid assuming a particular line-breaking character.
+# The extra dot is to prevent the shell from consuming trailing
+# line-breaks from the sub-command output.  A line-break within
+# single-quotes doesn't work because, if this script is created in a
+# platform that uses two characters for line-breaks (e.g., DOS), tr
+# would break.
+ac_LF_and_DOT=`echo; echo .`
+DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'`
+rm -f confdef2opt.sed
+
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_i=`echo "$ac_i" |
+	 sed 's/\$U\././;s/\.o$//;s/\.obj$//'`
+  # 2. Add them.
+  ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext"
+  ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+  set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)$' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+  	  /^X\/\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\/\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x$as_lineno_3"  = "x$as_lineno_2"  || {
+  # Find who we are.  Look in the path if we contain no path at all
+  # relative or not.
+  case $0 in
+    *[\\/]* ) as_myself=$0 ;;
+    *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+       ;;
+  esac
+  # We did not find ourselves, most probably we were run as `sh COMMAND'
+  # in which case we are not to be found in the path.
+  if test "x$as_myself" = x; then
+    as_myself=$0
+  fi
+  if test ! -f "$as_myself"; then
+    { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
+echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+  case $CONFIG_SHELL in
+  '')
+    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for as_base in sh bash ksh sh5; do
+	 case $as_dir in
+	 /*)
+	   if ("$as_dir/$as_base" -c '
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x$as_lineno_3"  = "x$as_lineno_2" ') 2>/dev/null; then
+	     $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+	     $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+	     CONFIG_SHELL=$as_dir/$as_base
+	     export CONFIG_SHELL
+	     exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+	   fi;;
+	 esac
+       done
+done
+;;
+  esac
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line before each line; the second 'sed' does the real
+  # work.  The second script uses 'N' to pair each line-number line
+  # with the numbered line, and appends trailing '-' during
+  # substitution so that $LINENO is not a special case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # second 'sed' script.  Blame Lee E. McMahon for sed's syntax.  :-)
+  sed '=' <$as_myself |
+    sed '
+      N
+      s,$,-,
+      : loop
+      s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+      t loop
+      s,-$,,
+      s,^['$as_cr_digits']*\n,,
+    ' >$as_me.lineno &&
+  chmod +x $as_me.lineno ||
+    { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
+echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensible to this).
+  . ./$as_me.lineno
+  # Exit status is that of the last command.
+  exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+  *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T='	' ;;
+  *c*,*  ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+  *)       ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  # We could just check for DJGPP; but this test a) works b) is more generic
+  # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+  if test -f conf$$.exe; then
+    # Don't use ln at all; we don't have any links
+    as_ln_s='cp -p'
+  else
+    as_ln_s='ln -s'
+  fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" 	$as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+exec 6>&1
+
+# Open the log real soon, to keep \$[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.  Logging --version etc. is OK.
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+} >&5
+cat >&5 <<_CSEOF
+
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.59.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+_CSEOF
+echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
+echo >&5
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+  echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+  echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+  echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+  echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number, then exit
+  -q, --quiet      do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+  --file=FILE[:TEMPLATE]
+		   instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to <bug-autoconf@gnu.org>."
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.59,
+  with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+srcdir=$srcdir
+INSTALL="$INSTALL"
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value.  By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=*)
+    ac_option=`expr "x$1" : 'x\([^=]*\)='`
+    ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  -*)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  *) # This is not an option, so the user has probably given explicit
+     # arguments.
+     ac_option=$1
+     ac_need_defaults=false;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --vers* | -V )
+    echo "$ac_cs_version"; exit 0 ;;
+  --he | --h)
+    # Conflict between --help and --header
+    { { echo "$as_me:$LINENO: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+   { (exit 1); exit 1; }; };;
+  --help | --hel | -h )
+    echo "$ac_cs_usage"; exit 0 ;;
+  --debug | --d* | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+    ac_need_defaults=false;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+   { (exit 1); exit 1; }; } ;;
+
+  *) ac_config_targets="$ac_config_targets $1" ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+  echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+  exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+
+
+
+
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_config_target in $ac_config_targets
+do
+  case "$ac_config_target" in
+  # Handling of arguments.
+  "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+  "jni/Makefile" ) CONFIG_FILES="$CONFIG_FILES jni/Makefile" ;;
+  "java/Makefile" ) CONFIG_FILES="$CONFIG_FILES java/Makefile" ;;
+  *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason to put it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+  trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+  trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` &&
+  test -n "$tmp" && test -d "$tmp"
+}  ||
+{
+  tmp=./confstat$$-$RANDOM
+  (umask 077 && mkdir $tmp)
+} ||
+{
+   echo "$me: cannot create a temporary directory in ." >&2
+   { (exit 1); exit 1; }
+}
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+
+#
+# CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "\$CONFIG_FILES"; then
+  # Protect against being on the right side of a sed subst in config.status.
+  sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+   s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s,@SHELL@,$SHELL,;t t
+s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s,@exec_prefix@,$exec_prefix,;t t
+s,@prefix@,$prefix,;t t
+s,@program_transform_name@,$program_transform_name,;t t
+s,@bindir@,$bindir,;t t
+s,@sbindir@,$sbindir,;t t
+s,@libexecdir@,$libexecdir,;t t
+s,@datadir@,$datadir,;t t
+s,@sysconfdir@,$sysconfdir,;t t
+s,@sharedstatedir@,$sharedstatedir,;t t
+s,@localstatedir@,$localstatedir,;t t
+s,@libdir@,$libdir,;t t
+s,@includedir@,$includedir,;t t
+s,@oldincludedir@,$oldincludedir,;t t
+s,@infodir@,$infodir,;t t
+s,@mandir@,$mandir,;t t
+s,@build_alias@,$build_alias,;t t
+s,@host_alias@,$host_alias,;t t
+s,@target_alias@,$target_alias,;t t
+s,@DEFS@,$DEFS,;t t
+s,@ECHO_C@,$ECHO_C,;t t
+s,@ECHO_N@,$ECHO_N,;t t
+s,@ECHO_T@,$ECHO_T,;t t
+s,@LIBS@,$LIBS,;t t
+s,@CC@,$CC,;t t
+s,@CFLAGS@,$CFLAGS,;t t
+s,@LDFLAGS@,$LDFLAGS,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
+s,@ac_ct_CC@,$ac_ct_CC,;t t
+s,@EXEEXT@,$EXEEXT,;t t
+s,@OBJEXT@,$OBJEXT,;t t
+s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
+s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
+s,@INSTALL_DATA@,$INSTALL_DATA,;t t
+s,@LN_S@,$LN_S,;t t
+s,@CPP@,$CPP,;t t
+s,@EGREP@,$EGREP,;t t
+s,@JAVA_HOME@,$JAVA_HOME,;t t
+s,@javagdbm_cv_path_javah@,$javagdbm_cv_path_javah,;t t
+s,@javagdbm_cv_path_java@,$javagdbm_cv_path_java,;t t
+s,@GDBM_LIBPATH@,$GDBM_LIBPATH,;t t
+s,@GDBM_INCLUDE@,$GDBM_INCLUDE,;t t
+s,@PKG@,$PKG,;t t
+s,@JNIINC@,$JNIINC,;t t
+s,@JNISUFFIX@,$JNISUFFIX,;t t
+s,@JNIFLAGS@,$JNIFLAGS,;t t
+s,@LIBOBJS@,$LIBOBJS,;t t
+s,@LTLIBOBJS@,$LTLIBOBJS,;t t
+CEOF
+
+_ACEOF
+
+  cat >>$CONFIG_STATUS <<\_ACEOF
+  # 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_lines=48
+  ac_sed_frag=1 # Number of current file.
+  ac_beg=1 # First line for current file.
+  ac_end=$ac_max_sed_lines # 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" $tmp/subs.sed >$tmp/subs.frag
+    else
+      sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+    fi
+    if test ! -s $tmp/subs.frag; then
+      ac_more_lines=false
+    else
+      # The purpose of the label and of the branching condition is to
+      # speed up the sed processing (if there are no `@' at all, there
+      # is no need to browse any of the substitutions).
+      # These are the two extra sed commands mentioned above.
+      (echo ':t
+  /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+      if test -z "$ac_sed_cmds"; then
+	ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+      else
+	ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+      fi
+      ac_sed_frag=`expr $ac_sed_frag + 1`
+      ac_beg=$ac_end
+      ac_end=`expr $ac_end + $ac_max_sed_lines`
+    fi
+  done
+  if test -z "$ac_sed_cmds"; then
+    ac_sed_cmds=cat
+  fi
+fi # test -n "$CONFIG_FILES"
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case $ac_file in
+  - | *:- | *:-:* ) # input from stdin
+	cat >$tmp/stdin
+	ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+	ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+  *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+	ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+  * )   ac_file_in=$ac_file.in ;;
+  esac
+
+  # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+  ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+  	  /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+  	  /^X\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+  { if $as_mkdir_p; then
+    mkdir -p "$ac_dir"
+  else
+    as_dir="$ac_dir"
+    as_dirs=
+    while test ! -d "$as_dir"; do
+      as_dirs="$as_dir $as_dirs"
+      as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+  	  /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+  	  /^X\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+    done
+    test ! -n "$as_dirs" || mkdir $as_dirs
+  fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+   { (exit 1); exit 1; }; }; }
+
+  ac_builddir=.
+
+if test "$ac_dir" != .; then
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A "../" for each directory in $ac_dir_suffix.
+  ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+  ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+  .)  # No --srcdir option.  We are building in place.
+    ac_srcdir=.
+    if test -z "$ac_top_builddir"; then
+       ac_top_srcdir=.
+    else
+       ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+    fi ;;
+  [\\/]* | ?:[\\/]* )  # Absolute path.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir ;;
+  *) # Relative path.
+    ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+  case "$ac_dir" in
+  .) ac_abs_builddir=`pwd`;;
+  [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+  *) ac_abs_builddir=`pwd`/"$ac_dir";;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+  case ${ac_top_builddir}. in
+  .) ac_abs_top_builddir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+  *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+  case $ac_srcdir in
+  .) ac_abs_srcdir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+  *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+  case $ac_top_srcdir in
+  .) ac_abs_top_srcdir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+  *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+  esac;;
+esac
+
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_builddir$INSTALL ;;
+  esac
+
+  if test x"$ac_file" != x-; then
+    { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+    rm -f "$ac_file"
+  fi
+  # Let's still pretend it is `configure' which instantiates (i.e., don't
+  # use $as_me), people would be surprised to read:
+  #    /* config.h.  Generated by config.status.  */
+  if test x"$ac_file" = x-; then
+    configure_input=
+  else
+    configure_input="$ac_file.  "
+  fi
+  configure_input=$configure_input"Generated from `echo $ac_file_in |
+				     sed 's,.*/,,'` by configure."
+
+  # First look for the input files in the build tree, otherwise in the
+  # src tree.
+  ac_file_inputs=`IFS=:
+    for f in $ac_file_in; do
+      case $f in
+      -) echo $tmp/stdin ;;
+      [\\/$]*)
+	 # Absolute (can't be DOS-style, as IFS=:)
+	 test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+   { (exit 1); exit 1; }; }
+	 echo "$f";;
+      *) # Relative
+	 if test -f "$f"; then
+	   # Build tree
+	   echo "$f"
+	 elif test -f "$srcdir/$f"; then
+	   # Source tree
+	   echo "$srcdir/$f"
+	 else
+	   # /dev/null tree
+	   { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+   { (exit 1); exit 1; }; }
+	 fi;;
+      esac
+    done` || { (exit 1); exit 1; }
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+  sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s,@configure_input@,$configure_input,;t t
+s,@srcdir@,$ac_srcdir,;t t
+s,@abs_srcdir@,$ac_abs_srcdir,;t t
+s,@top_srcdir@,$ac_top_srcdir,;t t
+s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t
+s,@builddir@,$ac_builddir,;t t
+s,@abs_builddir@,$ac_abs_builddir,;t t
+s,@top_builddir@,$ac_top_builddir,;t t
+s,@abs_top_builddir@,$ac_abs_top_builddir,;t t
+s,@INSTALL@,$ac_INSTALL,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+  rm -f $tmp/stdin
+  if test x"$ac_file" != x-; then
+    mv $tmp/out $ac_file
+  else
+    cat $tmp/out
+    rm -f $tmp/out
+  fi
+
+done
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || { (exit 1); exit 1; }
+fi
+
Index: /greenstone3/trunk/src/packages/javagdbm/configure.in
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/configure.in	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/configure.in	(revision 14125)
@@ -0,0 +1,193 @@
+dnl Process this file with autoconf to produce a configure script.
+
+dnl autoconf configuration script for the JNI part of the 
+dnl au.com.pharos.gdbm Java package
+dnl $Id$
+
+AC_REVISION($Revision$)
+
+# Copyright (C) 1997 by Pharos IP Pty Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+AC_INIT(jni/gdbmjava.c)
+
+dnl
+dnl look for libgdbm if not in standard location
+dnl
+AC_ARG_WITH(gdbm, [  --with-gdbm=dir         Use local gdbm library and headers], gdbmdir=$withval)
+
+# TODO: allow the user to specify whether they want a debugging
+# library or not?
+
+# check for compilers and other tools
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_LN_S
+
+AC_CHECK_SIZEOF(void *)
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(long)
+
+######## check for the JDK and tools within the JDK
+######## look in the JAVA_HOME environment variable at configure-time
+AC_MSG_CHECKING([for the JDK])
+if test "z$JAVA_HOME" != z &&
+   test -d $JAVA_HOME && 
+   test -d $JAVA_HOME/include
+then
+	AC_SUBST(JAVA_HOME)
+	AC_MSG_RESULT([found in $JAVA_HOME])
+else
+	AC_MSG_ERROR([not found in \$JAVA_HOME])
+fi
+
+# TODO: Check for specific header files in the JDK, or
+# functions/definitions within those headers?
+
+# TODO: guess which include directory to use under the JDK
+
+AC_PATH_PROG(javagdbm_cv_path_javah, javah, missing_javah)
+if test "$javagdbm_cv_path_javah" = missing_javah; then
+	AC_MSG_ERROR([javah not found.])
+fi
+
+AC_PATH_PROG(javagdbm_cv_path_java, java, missing)
+if test "$javagdbm_cv_path_java" = missing; then
+	AC_MSG_ERROR([java not found.])
+fi
+
+# check for gdbm library
+#AC_CHECK_LIB(gdbm, gdbm_open, [javagdbm_cv_lib_gdbm="-lgdbm"],
+#	[javagdbm_cv_lib_gdbm=no])
+#if test "$javagdbm_cv_lib_gdbm" = "no"; then
+#	AC_MSG_ERROR([no native gdbm library found.])
+#fi
+#LIBS="$javagdbm_cv_lib_gdbm"
+
+# gdbm stuff copied from gsdl [kjdon]
+
+dnl
+dnl Check that the GDBM library is available
+dnl
+dnl check libgdbm manually, in case it's not in the standard location.
+
+AC_MSG_CHECKING(that the GDBM library is available)
+if test ! -z "$gdbmdir" ; then
+  # look in given directory for header file
+  if test -r $gdbmdir/include/gdbm.h ; then
+    GDBM_INCLUDE="-I$gdbmdir/include" ;
+  elif test -r $gdbmdir/gdbm.h ; then
+    GDBM_INCLUDE="-I$gdbmdir" ;
+  fi
+
+  # look in given directory for library
+  if test -r $gdbmdir/libgdbm.a ; then
+    GDBM_LIBPATH="-L$gdbmdir" ;
+  elif test -r $gdbmdir/lib/libgdbm.a ; then
+    GDBM_LIBPATH="-L$gdbmdir/lib" ;
+  elif test -r $gdbmdir/.libs/libgdbm.a ; then
+    GDBM_LIBPATH="-L$gdbmdir/.libs" ;
+  fi
+
+  if test ! -z "$GDBM_LIBPATH" -a ! -z "$GDBM_INCLUDE" ; then
+    AC_MSG_RESULT($gdbmdir) ;
+  else
+    AC_MSG_RESULT(can't find gdbm.h and libgdbm.a in $gdbmdir);
+    AC_MSG_CHECKING(   looking for GDBM library in default locations)
+  fi
+fi
+
+# look in default path and in /usr/local
+if test -z "$GDBM_INCLUDE" ; then
+  # try in system directory 
+  AC_TRY_COMPILE(
+  [#include <gdbm.h>
+],
+  [],
+  success=yes,
+  success=no
+  )
+
+  if test $success = "no"; then
+# last chance - look in /usr/local (eg FreeBSD)
+    GDBM_LIBPATH=-L/usr/local/lib
+    GDBM_INCLUDE=-I/usr/local/include
+    ac_save_CXXFLAGS="$CXXFLAGS"
+    ac_save_LIBS="$LIBS"
+      CXXFLAGS="$CXXFLAGS -I/usr/local/include"
+      LIBS="$LIBS -L/usr/local/lib -lgdbm"
+      AC_TRY_LINK(
+  	[#include <gdbm.h>
+#include <stdio.h>
+	],
+  	[printf("%s",gdbm_version);],
+  	success=/usr/local,
+  	success=no
+      )
+      CXXFLAGS=$ac_save_CXXFLAGS
+      LIBS=$ac_save_LIBS
+  fi
+
+  AC_MSG_RESULT($success)
+  if test $success = "no"; then
+  AC_MSG_ERROR(GDBM Library not available - cannot install)
+  fi
+fi
+dnl I don't think anything actually checks this define, but...
+AC_DEFINE(HAVE_LIBGDBM , 1)
+
+AC_SUBST(GDBM_LIBPATH)
+AC_SUBST(GDBM_INCLUDE)
+
+########## set compiler options
+# TODO: is there a more appropriate way to guess which switches to use
+# with which systems/compilers?
+CFLAGS="-Wall -O2 -fpic"
+PKG="au.com.pharos.gdbm"
+AC_SUBST(CFLAGS)
+AC_SUBST(PKG)
+AC_SUBST(LIBS)
+
+# we need to set an extended JNI path for Mac OS/Darwin, as jni.h is on
+# a non-standard Path
+# is there a better way to do this??
+AC_MSG_CHECKING(for OS to set JNI options)
+# set defaults
+JNIINC=""
+JNISUFFIX="so"
+JNIFLAGS="-shared"
+
+if test "`(uname -s) 2> /dev/null`" = 'Darwin'; then
+  AC_MSG_RESULT(Darwin)
+  JNIINC="-I/System/Library/Frameworks/JavaVM.framework/Headers/ "
+  JNISUFFIX="jnilib"
+  JNIFLAGS="-dynamiclib -fno-common -single_module -framework JavaVM"
+fi
+if test "`(uname -s) 2> /dev/null`" = 'SunOS'; then
+  AC_MSG_RESULT(Solaris)
+  JNIINC="-I\$(JAVA_HOME)/include/solaris "
+fi
+if test "`(uname -s) 2> /dev/null`" = 'Linux'; then
+  AC_MSG_RESULT(Linux)
+  JNIINC="-I\$(JAVA_HOME)/include/linux "
+fi
+
+AC_SUBST(JNIINC)
+AC_SUBST(JNISUFFIX)
+AC_SUBST(JNIFLAGS)
+
+# write the output
+AC_OUTPUT([Makefile jni/Makefile java/Makefile])
Index: /greenstone3/trunk/src/packages/javagdbm/install-sh
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/install-sh	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/install-sh	(revision 14125)
@@ -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: /greenstone3/trunk/src/packages/javagdbm/java/Makefile.in
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/Makefile.in	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/Makefile.in	(revision 14125)
@@ -0,0 +1,31 @@
+# Makefile for Java part of JavaGDBM
+# Katherine Don, 2005
+
+JAVAC = $(JAVA_HOME)/bin/javac
+JAVAH = $(JAVA_HOME)/bin/javah
+JAR = $(JAVA_HOME)/bin/jar
+
+JAVAGDBMHOME=../
+JAVACLASSDIR=./classes
+JAVASRCDIR=.
+JAVACOPTIONS= -deprecation -g -O
+JAVACLASSPATH=$(JAVACLASSDIR):
+
+all: setup compile
+
+setup:
+	mkdir -p $(JAVACLASSDIR)
+
+compile: setup
+	$(JAVAC) -d $(JAVACLASSDIR) -sourcepath $(JAVASRCDIR) $(JAVACOPTIONS) au/com/pharos/*/*.java
+	$(JAVAH) -o $(JAVAGDBMHOME)/jni/GdbmFile.h -classpath $(JAVACLASSPATH) au.com.pharos.gdbm.GdbmFile
+	$(JAR) cf $(JAVAGDBMHOME)/javagdbm.jar -C $(JAVACLASSDIR) au
+
+clean:
+	rm -rf $(JAVACLASSDIR) $(JAVAGDBMHOME)/javagdbm.jar $(JAVAGDBMHOME)/jni/GdbmFile.h 
+
+install:
+
+distclean: clean
+	rm -f Makefile
+
Index: /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/dbinterface/vf/VFDbInterface.java
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/dbinterface/vf/VFDbInterface.java	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/dbinterface/vf/VFDbInterface.java	(revision 14125)
@@ -0,0 +1,37 @@
+/*
+ * (C) Pharos IP Pty Ltd 1997
+ */
+
+package au.com.pharos.dbinterface.vf;
+
+import java.util.Date;
+
+import au.com.pharos.gdbm.GdbmFile;
+
+import au.com.pharos.packing;
+
+import au.com.pharos.dbinterface.vf;
+
+public class VFDbInterface {
+
+  /* The Order database */
+  private String orderDB = "/fn/data/Orders.gdbm";
+
+  /* The Stock database */
+  private String stockDB = "/fn/data/Stock.gdbm";
+
+  /* Initialisation.  Nothing needs to happen yet. */
+  public VFDbInterface()
+  {
+    ;
+  }
+
+  /* Submit an order to the database */
+  public void submitOrder(VFOrder order)
+  {
+    GdbmFile db = new GdbmFile(orderDB);
+    db.setKeyPacking(new StringPacking());
+    db.setValuePacking(new QuotedVectorPacking());
+
+    Vector details = order.toVectorString();
+    
Index: /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/dbinterface/vf/VFItem.java
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/dbinterface/vf/VFItem.java	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/dbinterface/vf/VFItem.java	(revision 14125)
@@ -0,0 +1,106 @@
+/*
+ * (C) Pharos IP Pty Ltd 1997
+ */
+package au.com.pharos.dbinterface.vf;
+
+import java.util.Date;
+
+public class VFItem {
+
+  /* The title of the item */
+  public String title;
+
+  /* The name fo the item's distributor */
+  public String distributor;
+
+  /* The category of the item */
+  // TODO: Create a more appropriate type for this?
+  public String category;
+
+  /* The rating of the item */
+  //TODO: Again, a more appropriate type?
+  public String rating;
+
+  /* The list price */
+  public float listPrice;
+
+  /* The supplier's price */
+  public float ourPrice;
+
+  /* The release date for the item */
+  public Date releaseDate;
+
+  /* The date upon which the video is accessible to PayTV */
+  public Date payTVWindow;
+
+  /* The date upon which the video is accessible to free-to-air TV */
+  public Date tvWindow;
+
+  /* The sell-through beginning date */
+  public Date sellThruWindow;
+
+  /* Whether or not the item has an internal magazine advertisement */
+  public boolean magAdvert;
+
+  /* The recommended number of items for Budget 1 stores */
+  public short budget1;
+
+  /* For budget 2 stores */
+  public short budget2;
+
+  /* Budget 3 stores */
+  public short budget3;
+
+  /* Budget 4 stores */
+  public short budget4;
+
+  /* Will the item be advertised by the VideoIndustry Professional Association */
+  boolean vipa;
+
+  /* Initialise all the attributes */
+  public VFItem(String newTitle,
+		String newDistrib,
+		String newCat,
+		String newRating,
+		float newList,
+		float newPrice,
+		Date newRelease,
+		Date newPaytv,
+		Date newTv,
+		boolean isMagAdvert,
+		short newBudget1,
+		short newBudget2,
+		short newBudget3,
+		short newBudget4
+		boolean newvipa)
+  {
+    title = newTitle;
+    distributor = newDistrib;
+    category = newCat;
+    rating = newRating;
+    listPrice = newList;
+    ourPrice = newPrice;
+    releaseDate = newRelease;
+    payTVWindow = newPaytv;
+    tvWindow = newTv;
+    magAdvert = isMagAdvert;
+    budget1 = newBudget1;
+    budget2 = newBudget2;
+    budget3 = newBudget3;
+    budget4 = newBudget4;
+    vipa = newvipa;
+  }
+
+  public boolean equals (Object o)
+  {
+    if (!(o instanceof VFItem)) {
+      return false;
+    }
+    VFItem other = (VFItem) o;
+    if (title.equals(other.title) && distributor.equals(other.distributor) && category.equals(other.category)) {
+      return true;
+    }
+    return false;
+  }
+
+}
Index: /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/dbinterface/vf/VFOrder.java
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/dbinterface/vf/VFOrder.java	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/dbinterface/vf/VFOrder.java	(revision 14125)
@@ -0,0 +1,116 @@
+/*
+ * (C) Pharos IP PTy Ltd 1997
+ */
+
+package au.com.pharos.dbinterface.vf;
+
+import java.util.Date;
+import java.util.Vector;
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+import java.text.SimpleDateFormat;
+import java.text.ParsePosition;
+
+import java.text.SimpleDateFormat;
+
+public class VFOrder {
+
+  /* The final date for submission */
+  public Date finalSubmit;
+
+  /* The date the order was created */
+  public Date orderDate;
+
+  /* A hash mapping titles requested to numbers of each title*/
+  public Hashtable orderNumbers;
+  
+  /* The name of the ordering store */
+  public String name;
+
+  public VFOrder(Date newFinal,
+		 String newName,
+		 Hashtable newOrder)
+  {
+    finalSubmit = newFinal;
+    orderNumbers = newOrder;
+    name = newName;
+    orderDate = new Date(System.currentTimeMillis());
+    if (orderDate.after(finalSubmit)) {
+      throw new IllegalArgumentException("Final submission date is earlier than present date.");
+    }
+  }
+
+  public VFOrder(Date newFinal,
+		 Date newDate,
+		 String newName,
+		 Hashtable newOrder)
+  {
+    finalSubmit = newFinal;
+    orderDate = newDate;
+    orderNumbers = newOrder;
+    name = newName;
+    orderDate = new Date(System.currentTimeMillis());
+    if (orderDate.after(finalSubmit)) {
+      throw new IllegalArgumentException("Final submission date is earlier than present date.");
+    }
+  }
+
+  public Vector toVectorString()
+  {
+    Vector result = new Vector();
+    result.addElement(new Long(finalSubmit.getTime()));
+    result.addElement(new Long(orderDate.getTime()));
+    result.addElement(orderNumbers.toString());
+    result.addElement(name);
+    return result;
+  }
+
+  public VFOrder fromVectorString(Vector input)
+       throws java.text.ParseException
+  {
+    Hashtable data = new Hashtable();
+    SimpleDateFormat form = new SimpleDateFormat();
+    for (Enumeration e = input.elements(); e.hasMoreElements(); ) {
+      System.out.println(e.nextElement());
+    }
+    try {
+      finalSubmit = new Date(((Long) input.elementAt(0)).longValue());
+    } catch (NullPointerException e) {
+      System.err.println("Waaaah!");
+      finalSubmit = new Date();
+    }
+    System.err.println("No 2:" + input.elementAt(1).toString());
+    orderDate = new Date(((Long) input.elementAt(1)).longValue());
+    name = (String) input.elementAt(3);
+    String hashString = (String) input.elementAt(2);
+    StringBuffer key = new StringBuffer();;
+    StringBuffer value = new StringBuffer();
+    String type = new String("key");
+    for (int count = 0; count < hashString.length(); count++) {
+      char i = hashString.charAt(count);
+      if (i == '{' || i == ' ') { ; }
+      else if (i == '}') { data.put(key, value); }
+      else if (i == ',') {data.put(key, value); }
+      else if (i == '=') {
+	if (type.equals("key")) {
+	  type = "value";
+	} else {
+	  type = "key";
+	}
+      } else {
+	if (type.equals("key")) {
+	  key.append(i);
+	} else {
+	  value.append(i);
+	}
+      }
+    }
+    return new VFOrder(finalSubmit, orderDate, name, data);
+  }
+	
+      
+
+
+}
+  
Index: /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/gdbm/Closeable.java
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/gdbm/Closeable.java	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/gdbm/Closeable.java	(revision 14125)
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 1997 Pharos IP Pty Ltd
+ * Confidential.  All rights reserved.
+ * $Id$
+ */
+
+package au.com.pharos.gdbm;
+
+import java.io.IOException;
+
+/** A Closeable object is one having a connection to an underlying
+ * data store that may be flushed or closed.
+ *
+ * <P>This interface is intended to complement the Dictionary and
+ * Collection interfaces by reflecting the fact that many such objects
+ * may be closed.
+ *
+ * @author Martin Pool
+ * @version $Revision$
+ **/
+public interface Closeable {
+    /** Write outstanding changes to the underlying database, and
+     * break the connection, freeing any associated resources or
+     * locks.  This generally does not imply that the data will be
+     * lost, merely that it will be released.  If this is not
+     * meaningful for a particular Closeable object, then it should be
+     * a no-op.
+     *
+     * @exception java.io.IOException passed up from the underlying
+     * database.
+     **/
+    public void close() throws IOException;
+
+    /** Write outstanding changes to the underlying database, but
+     * leave the database open.  If this is not meaningful for a
+     * particular Closeable object, then it should be a no-op.
+     *
+     * @exception java.io.IOException passed up from the underlying
+     * database.
+     **/
+    public void sync() throws IOException;
+}
Index: /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/gdbm/GdbmDictionary.java
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/gdbm/GdbmDictionary.java	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/gdbm/GdbmDictionary.java	(revision 14125)
@@ -0,0 +1,157 @@
+/*
+ * module: pip/java/gdbm -- A Java interface to the GDBM library
+ * class:  GdbmDictionary -- Wrap up a GDBM File for use as a Dictionary
+ *
+ * Copyright (C) 1997 Pharos IP Pty Ltd
+ * $Id$
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the 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 au.com.pharos.gdbm;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+
+/** A GDBM database, presented as a Java dictionary.
+ *
+ * <P>This is a separate class which defers most operations to
+ * GdbmFile because GdbmFile can throw IO exceptions, and because the
+ * interface assumptions for Dictionary are not the same as those of
+ * the IO library.  Perhaps they should be the same.
+ *
+ * <P>The Dictionary class will be partially replaced by the much
+ * more elegant 
+ * <A HREF="http://www.javasoft.com/products/jdk/preview/docs/guide/collections/overview.html">Collections API</A>
+ * in JDK1.2, at which time a GDBM Collections interface will probably
+ * be available.
+ *
+ * @see java.util.Dictionary
+ * @see GdbmFile
+ *
+ * @author Martin Pool
+ * @version $Revision$
+ **/
+// TODO: I wonder if this should be an inner class of GdbmFile?  It
+// would bloat that source file a bit, but would (arguably) more
+// accurately capture the intended design. -- mbp
+public class GdbmDictionary extends Dictionary implements Closeable
+{
+    // XXX: This should probably become a private field, but on the other
+    // hand it's probably useful to be able to apply GDBM-specific methods to
+    // the underlying DB.  -- mbp
+    GdbmFile db;
+
+    public GdbmDictionary(GdbmFile db) {
+	this.db = db;
+    }
+
+    private Exception caughtException;
+    
+    public Exception checkError() {
+	return caughtException;
+    }	
+
+    public int size() {
+	try {
+	    return db.size();
+	} catch (Exception e) {
+	    caughtException = e;
+	    return 0;
+	}
+    }
+
+    public boolean isEmpty() {
+	try {
+	    return db.isEmpty();
+	} catch (Exception e) {
+	    caughtException = e;
+	    return false;
+	}
+    }
+
+    public Enumeration keys() {
+	try {
+	    return db.keys();
+	} catch (Exception e) {
+	    caughtException = e;
+	    return null;
+	}
+    }
+
+    public Enumeration elements() {
+	// TODO: write an iterator class to do this
+	throw new NoSuchMethodError();
+    }
+
+    public Object get(Object key) {
+	try {
+	    return db.fetch(key);
+	} catch (Exception e) {
+	    caughtException = e;
+	    return null;
+	}
+    }
+
+    public Object put(Object key, Object value)  {
+	try {
+	    Object oldValue = db.fetch(key);
+	    db.store(key, value);
+	    return oldValue;
+	} catch (Exception e) {
+	    caughtException = e;
+	    return null;
+	}
+    }
+
+    public Object remove(Object key) {
+	try {
+	    Object oldValue = db.fetch(key);
+	    db.delete(key);
+	    return oldValue;
+	} catch (Exception e) {
+	    caughtException = e;
+	    return null;
+	}
+    }
+
+    /** Write outstanding changes to the underlying database, and
+     * close the database.
+     *
+     * @see au.com.pharos.gdbm.Closeable
+     **/
+    public void close() {
+	try {
+	    if (db != null && db.isOpen())
+		db.close();
+	    db = null;
+	} catch (GdbmException e) {
+	    ;
+	}
+    }
+
+    /** Write outstanding changes to the underlying database, but
+     * leave the database open.
+     *
+     * @see au.com.pharos.gdbm.Closeable
+     **/
+    public void sync() {
+	try {
+	    db.sync();
+	} catch (GdbmException e) {
+	    ;
+	}
+    }
+}
Index: /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/gdbm/GdbmException.java
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/gdbm/GdbmException.java	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/gdbm/GdbmException.java	(revision 14125)
@@ -0,0 +1,45 @@
+/*
+ * module: pip/java/gdbm -- A Java interface to the GDBM library
+ * class:  GdbmException -- An exception originating in the GDBM library
+ * Copyright (C) 1997 Pharos IP Pty Ltd
+ * $Id$
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the 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 au.com.pharos.gdbm;
+
+import java.io.IOException;
+
+/** An exception originating in the GDBM library.
+ *
+ * @author Martin Pool
+ * @version $Revision$ 
+ * @see au.com.pharos.gdbm.GdbmFile
+ */
+
+public class GdbmException extends IOException
+{
+    // TODO: Perhaps provide more information about which particular
+    // exception caused the problem?
+    /** Constructs a GdbmException with the specified reason.
+    **/
+    public GdbmException(String reason)
+    {
+	super(reason);
+    }
+}
+
+
Index: /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/gdbm/GdbmFile.java
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/gdbm/GdbmFile.java	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/gdbm/GdbmFile.java	(revision 14125)
@@ -0,0 +1,563 @@
+/*
+ * Copyright (C) 1997 Pharos IP Pty Ltd
+ * $Id$
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the 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 au.com.pharos.gdbm;
+
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+import au.com.pharos.packing.Packing;
+import au.com.pharos.packing.RawPacking;
+
+/** Java interface to a GDBM database table.
+ *
+ * <P>This database is a simple on-disk hash table.
+ *
+ * <P>Both the hash keys and values
+ * are binary strings of any length.  They are converted to and
+ * from Java objects using customizable packing strategies.
+ *
+ * <P>The implementation of this class consists of two levels: a
+ * Java-level interface, and a set of private native functions
+ * implemented in C.  As much functionality as possible is implemented
+ * in Java: the C functions generally just marshal the information for
+ * presentation to the native GDBM library.
+ *
+ * <P>The native library <CODE>gdbmjava</CODE> must be available
+ * for dynamic loading in a system-dependant manner.
+ *
+ * <p>See the GDBM documentation file, and the
+ * <A HREF="http://www.pharos.com.au/gdbm/">JavaGDBM home page</A>
+ * for more information.
+ *
+ * @see au.com.pharos.packing.Packing
+ * @see au.com.pharos.gdbm.GdbmTest
+ * @see au.com.pharos.gdbm.GdbmDictionary
+ *
+ * @author Martin Pool
+ * @version $Revision$
+ **/
+
+public class GdbmFile implements Closeable {
+    /** The GDBM handle for the database file, or 0 if the database has
+     * been closed.  Java doesn't understand it, but it stores it and
+     * passes it to the C routines. */
+    private transient volatile long dbf;
+
+    // Remember the parameters used to open the database
+    private int openFlags;
+    private String dbFilename;
+
+    // -----------------------------------------------------------------
+    // Constructors
+
+    // Values must match those from gdbm.h !
+    /** Indicates that the caller will just read the database.  Many
+     * readers may share a database. */
+    public final static int READER = 0;
+
+    /** The caller wants read/write access to an existing database and
+     * requires exclusive access. */
+    public final static int WRITER = 1;
+
+    /** The caller wants exclusive read/write access, and the database
+     * should be created if it does not already exist. */
+    public final static int WRCREAT = 2;
+
+    /** The caller wants exclusive read/write access, and the database
+     * should be replaced if it already exists. */
+    public final static int NEWDB = 3;
+
+    /** Flag indicating GDBM should write to the database without disc
+     * synchronization.  This allows faster writes, but may produce an
+     * inconsistent database in the event of abnormal termination of
+     * the writer. */
+    public final static int FAST = 16;
+
+    // TODO: Allow FAST mode to be toggled
+
+    /** Creates a new GdbmFile object representing an disk database.  The
+     * database is opened or created on disk.
+     *
+     * <P>Both key and value strategies default to
+     * RawPacking, meaning that the database will use raw byte arrays
+     * for both key and value.
+     *
+     * <P>TODO: Allow the caller to specify the block size and/or
+     * cache size.
+     *
+     * @param fileName the disk filename in which the data will be stored.
+     *
+     * @param flags any of READER, WRITER, WRCREAT, and NEWDB, optionally
+     * ORed with FAST
+     *
+     * @exception GdbmException if the database cannot be opened or
+     * created.
+     *
+     * @see GdbmFile#READER
+     * @see GdbmFile#WRITER
+     * @see GdbmFile#WRCREAT
+     * @see GdbmFile#NEWDB
+     * @see GdbmFile#FAST
+     */
+    public GdbmFile(String fileName, int flags)
+	 throws GdbmException
+    {
+	openFlags = flags;
+	dbFilename = fileName;
+	keyPacking = new RawPacking();
+	valuePacking = new RawPacking();
+	dbf = gdbm_open(fileName, flags);
+    }
+
+    /** Close the database file if it is still open.
+     *
+     * <P><B>Note</B> that the disk file is locked against access from
+     * other processes while it is open.  To prevent contention, it
+     * may be useful to explicitly close the file rather than waiting
+     * for the garbage-collector.
+     *
+     * @see GdbmFile#isOpen()
+     **/
+    public synchronized void close() throws GdbmException
+    {
+	if (dbf != 0)
+	    gdbm_close(dbf);
+	dbf = 0;		// No longer connected
+    }
+
+    /** Close the database when the GdbmFile is garbage-collected.
+     *
+     * @see GdbmFile#close()
+     */
+    public void finalize() throws GdbmException
+    {
+	close();
+    }
+
+    /* The Gdbm file is unlocked when the process terminates, but
+     * nevertheless it would be good to close it in finalization, in
+     * case the OS process continues after the JVM terminates.
+     *
+     * XXX: Unfortunately, anybody else can turn this off again: it
+     * would be nice if there was a way to avoid this. */
+    static {
+	System.runFinalizersOnExit(true);
+    }
+
+
+
+    // -----------------------------------------------------------------
+    // Packing strategies
+    private Packing keyPacking, valuePacking;
+
+    /** Set the object to be used as the packing strategy for
+     * converting key objects to and from the byte arrays stored in
+     * the database.
+     *
+     * <P>Depending on the class of Java object used as the key of your
+     * database, it may be appropriate to use a packing strategy from
+     * the
+     * <A HREF="Package-au.com.pharos.packing.html"><CODE>au.com.pharos.packing</CODE></A>
+     * package, or to define a new subclass of one of those strategies.
+     *
+     * @see au.com.pharos.packing.Packing
+     * @see GdbmFile#setValuePacking(au.com.pharos.packing.Packing)
+     **/
+    public void setKeyPacking(Packing newPacking) {
+	keyPacking = newPacking;
+    }
+
+    /** Set the object to be used as the packing strategy for
+     * converting value objects to and from the byte arrays stored
+     *  in the database.
+     *
+     * <P>Depending on the class of Java object used as the key of your
+     * database, it may be appropriate to use a packing strategy from
+     * the
+     * <A HREF="Package-au.com.pharos.packing.html"><CODE>au.com.pharos.packing</CODE></A>
+     * package, or to define a new subclass of one of those strategies.
+     *
+     * @see au.com.pharos.packing.Packing
+     * @see GdbmFile#setKeyPacking(au.com.pharos.packing.Packing )
+     **/
+    public void setValuePacking(Packing newPacking) {
+	valuePacking = newPacking;
+    }
+
+    // -----------------------------------------------------------------
+
+    /** Returns a string indicating the version of the underlying GDBM
+     * library.
+     *
+     * @return the version of the native GDBM library.
+     **/
+    public static String getLibraryVersion()
+    {
+	return gdbm_getversion();
+    }
+
+    /** Return a string indicating the version of the JavaGDBM library
+     * wrapper.
+     *
+     * <P>The most current release is available from the
+     * <A HREF="http://www.pharos.com.au/javagdbm/">JavaGDBM home page</A>.
+     *
+     * @return the release number of the JavaGDBM library
+     **/
+    public static String getWrapperVersion()
+    {
+	return gdbm_wrapperVersion();
+    }
+
+    /** Indicate whether the database is writable.
+     *
+     * <P>Databases are opened in either read-write or read-only mode,
+     * and remain in that mode until they are closed.
+     *
+     * @return true if the database may be written; otherwise false.
+     *
+     * @see GdbmFile#GdbmFile(java.lang.String, int)
+     **/
+    public boolean isWritable()
+    {
+	return (openFlags & 0x03) != READER;
+    }
+
+    /** Indicate whether the database is open or not.
+     *
+     * <P>A database is open from the point of creation until close()
+     * is called, if ever, after which it is closed.
+     *
+     * @return false if the database has been closed; otherwise true.
+     *
+     * @see GdbmFile#close()
+     **/
+    public boolean isOpen()
+    {
+	return dbf != 0;
+    }
+
+
+    /** Compact the database file.
+     *
+     * <P>If you have had a lot of deletions and would like to shrink the
+     * space used by the GDBM file, this function will reorganize the
+     * database.  GDBM will not shorten the length of a GDBM file
+     * (deleted file space will be reused) except by using this
+     * reorganization, though it will reuse the vacant space.
+     *
+     * <P>The database must be writable.
+     */
+    public void reorganize()
+	 throws GdbmException
+    {
+	gdbm_reorganize(dbf);
+    }
+    
+
+    /** Flush changes to disk.
+     *
+     * <P>This function is only required when the database is
+     * opened with the FAST flag set.  By default, changes are
+     * flushed to disk after every update.
+     *
+     * <P>The database must be writable.
+     *
+     * @see GdbmFile#FAST
+     **/
+    public void sync()
+	 throws GdbmException
+    {
+	gdbm_sync(dbf);
+    }
+
+
+
+    /** Retrieve the value corresponding to a particular key.
+     *
+     * @param key the key of the record to be retrieved
+     *
+     * @return the value of the record with the specified key; or
+     * null if the key is not present in the database.
+     */
+    public Object fetch(Object key) throws GdbmException
+    {
+	byte[] keyBytes = keyPacking.toBytes(key);
+	return valuePacking.fromBytes(gdbm_fetch(dbf, keyBytes));
+    }
+
+
+    /** Indicate whether the specified key is in the database,
+     * without returning the value.
+     *
+     * @param key the key of the record to be retrieved
+     *
+     * @return true if a record with the specified key is present;
+     * otherwise false.
+     */
+    public boolean exists(Object key) throws GdbmException
+    {
+	byte[] keyBytes = keyPacking.toBytes(key);
+	return gdbm_exists(dbf, keyBytes);
+    }
+
+
+
+    /** Store a value in the database, replacing any existing value
+     * with the same key.
+     *
+     * @param key key under which to store the value
+     *
+     * @param value value to be stored
+     *
+     * @exception GdbmException if the object is a reader; or
+     * if an IO error occurs
+     **/
+    public void store(Object key, Object value)
+	 throws GdbmException
+    {
+	byte[] keyBytes = keyPacking.toBytes(key);
+	byte[] valueBytes = valuePacking.toBytes(value);
+	gdbm_store(dbf, keyBytes, valueBytes, true);
+    }
+
+
+    
+    /** Store a value in the database, unless a record with the same
+     * key already exists.
+     *
+     * @param key key under which to store the value.
+     *
+     * @param value value to be stored.
+     *
+     * @exception GdbmException if a record with the specified key
+     * already exists; or if the object is a reader; or
+     * if an IO error occurs
+     */
+    public void storeNoReplace(Object key, Object value)
+	 throws GdbmException
+    {
+	byte[] keyBytes = keyPacking.toBytes(key);
+	byte[] valueBytes = valuePacking.toBytes(value);
+ 	gdbm_store(dbf, keyBytes, valueBytes, false);
+    }
+
+
+    
+    /** Remove a record from the database.
+     *
+     * @param key key of the record to be removed
+     *
+     * @exception GdbmException if there is no record with the
+     * specified key; or if the object is a reader; or if an IO error
+     * occurs.
+     **/
+    public void delete(Object key)
+	 throws GdbmException
+    {
+	byte[] keyBytes = keyPacking.toBytes(key);
+	gdbm_delete(dbf, keyBytes);
+    }
+
+
+
+
+
+    // -----------------------------------------------------------------
+    // Iterator support
+
+    // TODO: Use a flag/timestamp approach to throw an exception if
+    // somebody modifies the database while they're trying to iterate
+    // over it?  Approach suggested by Doug Lea's Collections API. --
+    // mbp
+
+    /** Return an enumeration which will return all of the keys for the
+     * database of the file in (apparently) random order.
+     *
+     * <P><B>Caution:</B> If the database is modified while
+     * an enumeration is in progress,
+     * then changes in the hash table may cause the enumeration to
+     * miss some records.
+     *
+     * @see java.util.Enumeration
+     **/
+    public Enumeration keys() throws GdbmException
+    {
+	// Return an inner class which will do the iteration in the
+	// context of this GdbmFile object.
+	return new KeyEnumeration();
+    }
+
+    // Synchronization is performed in the GdbmFile's methods
+    class KeyEnumeration implements Enumeration {
+	private byte[] currKey, nextKey;
+
+	KeyEnumeration() throws GdbmException {
+	    currKey = null;
+	    nextKey = getFirstKeyRaw();
+	}
+
+	public boolean hasMoreElements() {
+	    return nextKey != null;
+	}
+
+	public Object nextElement() throws NoSuchElementException {
+	    try {
+		currKey = nextKey;
+		if (currKey == null)
+		    throw new NoSuchElementException();
+		else
+		    nextKey = getNextKeyRaw(currKey);
+		return keyPacking.fromBytes(currKey);
+	    } catch ( GdbmException e ) {
+		// Can't propagate this through java.util.Enumeration, dammit
+		throw new NoSuchElementException();
+	    }
+	}
+    }
+
+    /** Start a visit to all keys in the hashtable, using raw data values.
+     *
+     * @return the first key in the hash table as a byte array; or null if
+     * the database is empty. */
+    byte[] getFirstKeyRaw() throws GdbmException
+    {
+	return gdbm_firstkey(dbf);
+    }
+
+    /** Return the first record in the hashtable.
+     *
+     * <P>Note that the database
+     * is not ordered, so the key returned is simply the first in the
+     * hashtable and effectively randomly selected.
+     *
+     * @return the first key in the hash table; or null if
+     * the database is empty.
+     *
+     * @see GdbmFile#getNextKey(java.lang.Object)
+     * @see GdbmFile#keys()
+     **/
+    Object getFirstKey() throws GdbmException
+    {
+	return keyPacking.fromBytes(getFirstKeyRaw());
+    }
+
+
+    /** Find and read the next key in the hashtable.
+     *
+     * @return the next key; or null if <EM>keyBytes</EM> is the last key
+     * in the hashtable.
+     **/
+    byte[] getNextKeyRaw(byte[] keyBytes) throws GdbmException
+    {
+	return gdbm_nextkey(dbf, keyBytes);
+    }
+
+
+    /** Check whether the database is empty.
+     *
+     * @return true if the database contains no records; otherwise
+     * false.
+     **/
+    public boolean isEmpty() throws GdbmException
+    {
+	return getFirstKeyRaw() == null;
+    }
+
+
+    /** Count the records in the database.
+     *
+     * <P>This is implemented by iterating over the database, and so is
+     * a fairly expensive operation.
+     *
+     * <P>This method locks the database to make sure the count is
+     * accurate.
+     *
+     * @return the number of records in the database
+     * @see GdbmFile#isEmpty()
+     **/
+    public synchronized int size() throws GdbmException
+    {
+	int s = 0;
+	byte[] key = getFirstKeyRaw();
+	while (key != null) {
+	    s++;
+	    key = getNextKeyRaw(key);
+	}
+	return s;
+    }
+
+
+    static {
+	String libraryFile = System.getProperty
+	    ("au.com.pharos.gdbm.libraryFile");
+
+	if (libraryFile != null) {
+	    System.load(libraryFile);
+	} else {
+	    System.loadLibrary("gdbmjava");
+	}
+    }
+
+    private synchronized native long
+    gdbm_open(String fileName, int flags)
+	 throws GdbmException;
+
+    private synchronized native void
+    gdbm_close(long dbf);
+
+    private synchronized native void
+    gdbm_store(long dbf,
+	       byte[] key,
+	       byte[] content,
+	       boolean replace);
+
+    private synchronized native byte[]
+    gdbm_fetch(long dbf,
+	       byte[] key);
+
+    private synchronized native boolean
+    gdbm_exists(long dbf,
+		byte[] key);
+
+    private synchronized native void
+    gdbm_delete(long dbf,
+		byte[] key);
+
+    private synchronized native byte[]
+    gdbm_firstkey(long dbf)
+	 throws GdbmException;
+
+    private synchronized native byte[]
+    gdbm_nextkey(long dbf, byte[] key)
+	 throws GdbmException;
+
+    private synchronized static native String
+    gdbm_getversion();
+
+    private synchronized static native String
+    gdbm_wrapperVersion();
+
+    private synchronized native void
+    gdbm_reorganize(long dbf);
+
+    private synchronized native void
+    gdbm_sync(long dbf);
+}
Index: /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/gdbm/GdbmTest.java
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/gdbm/GdbmTest.java	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/gdbm/GdbmTest.java	(revision 14125)
@@ -0,0 +1,296 @@
+/*
+ * module: pip/java/gdbm -- A Java interface to the GDBM library
+ * class:  GdbmTest -- Test suite for this package
+ * Copyright (C) 1997 Pharos IP Pty Ltd
+ * $Id$
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the 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 au.com.pharos.gdbm;
+
+import java.io.PrintStream;
+
+import java.util.Enumeration;
+
+import au.com.pharos.test.Test;
+import au.com.pharos.packing.Packing;
+import au.com.pharos.packing.StringPacking;
+import au.com.pharos.packing.RawPacking;
+
+/** Test harness for the Gdbm library.
+ *
+ * <P>The source of this class forms a useful demonstration of the
+ * JavaGDBM library and is commended to the intending programmer.
+ *
+ * <P>More test cases would be very welcome.
+ *
+ * @see au.com.pharos.gdbm.GdbmFile
+ * @see au.com.pharos.packing.Packing
+ * @author Martin Pool
+ * @version $Revision$
+ */
+public class GdbmTest {
+    // Don't instantiate
+    private GdbmTest() { ; }
+    
+    private static void testLongData(GdbmFile db)
+	 throws Exception
+    {
+	StringBuffer lgBuffer = new StringBuffer();
+	for (int i = 0; i < 100; i++)
+	    lgBuffer.append("ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890" +
+			    "ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890" +
+			    "ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890");
+
+	String lgString = lgBuffer.toString();
+	lgBuffer = null;
+	String smallKey = "largeDatum";
+
+	db.store(smallKey, lgString);
+	String retr = (String) db.fetch(smallKey);
+
+	Test.ok(9, retr.hashCode() == lgString.hashCode());
+	Test.ok(10, retr.equals(lgString));
+
+	db.delete(smallKey);
+	Test.ok(11, true);
+
+	db.reorganize();
+	Test.ok(12, true);
+    }
+
+
+    static final int MANY_RECORDS = 200;
+    
+    private static void testBigFile(GdbmFile db)
+	 throws Exception
+    {
+	String key;
+
+	// Test a lot of data
+	byte[] bigData = new byte[10000];
+	for (int i = 0; i < bigData.length; i++)
+	    bigData[i] = (byte)((i & 63) + 32);
+	db.setValuePacking(new RawPacking());
+	Test.ok(150, true);
+
+	// Store a series of records in the file
+	for (int i = 0; i < MANY_RECORDS; i++) {
+	    if ((i % 100) == 0)
+		System.out.print(Integer.toString(i)+ " ");
+	    db.store(Integer.toString(i, 16), bigData);
+	}
+	System.out.println();
+	Test.ok(151, true);
+
+	// Enumerate keys and values out of the file
+	int count = 0;
+	Enumeration keys = db.keys();
+	while ( keys.hasMoreElements() ) {
+	    key = (String) keys.nextElement();
+	    count++;
+	    if ((count % 100) == 0)
+		System.out.print(Integer.toString(count)+ " ");
+	}
+	System.out.println();
+	Test.ok(152, count==MANY_RECORDS);
+
+	// Delete all the records from the file
+	count = 0;
+	while ( (key = (String) db.getFirstKey()) != null ) {
+	    db.delete(key);
+	    count++;
+	    if ((count % 100) == 0)
+		System.out.print(Integer.toString(count)+ " ");
+	}
+	System.out.println();
+	Test.ok(153, count==MANY_RECORDS);
+
+	db.reorganize();
+	Test.ok(154, true);
+    }
+
+    public static void main(String[] argv) {
+	try {
+	    final String dbFile = "/tmp/java.gdbm";
+	    String key, value;
+	    boolean found;
+
+	    // Test cases, inspired by db-hash.t in the Perl5.003_93
+	    // distribution
+	    System.out.print("GDBM Database tests:\n\t" +
+			     GdbmFile.getLibraryVersion() + "\n\t" +
+			     GdbmFile.getWrapperVersion() + "\n");
+
+	    // Create a simple database
+	    GdbmFile db = new GdbmFile(dbFile, GdbmFile.NEWDB);
+	    Test.ok(1, db != null);
+
+	    // Set the packing strategy
+	    db.setKeyPacking(new StringPacking());
+	    db.setValuePacking(new StringPacking());
+
+	    // Store some data in the file
+	    db.store("mountain", "Kosciusko");
+	    Test.ok(2, true);
+
+	    // Store and read back data
+	    db.storeNoReplace("abc", "ABC");
+	    Test.ok(3, ((String) db.fetch("abc")).equals("ABC"));
+
+	    // Check whether keys exist or not
+	    Test.ok(4, db.exists("abc"));
+	    Test.ok(5, !db.exists("jimmy"));
+	    Test.ok(6, !db.exists("abc\0"));
+
+	    // Delete those records
+	    db.delete("abc");
+	    db.delete("mountain");
+
+	    Test.ok(10, !db.exists("abc"));
+	    Test.ok(11, !db.exists("mountain"));
+
+	    // Store a series of records in the file
+	    for (int i = 100; i < 200; i++)
+		db.storeNoReplace(Integer.toString(i, Character.MAX_RADIX),
+				  Integer.toString(i, Character.MIN_RADIX));
+
+	    // Enumerate keys and values out of the file
+	    int count = 0;
+	    Enumeration keys = db.keys();
+	    while ( keys.hasMoreElements() ) {
+		key = (String) keys.nextElement();
+		// System.out.print(key + "=");
+		// value = (String) db.fetch(key);
+		// System.out.println(value);
+		count++;
+	    }
+	    Test.ok(20, count==100);
+
+	    // Delete all the records from the file
+	    count = 0;
+	    while ( (key = (String) db.getFirstKey()) != null ) {
+		db.delete(key);
+		count++;
+	    }
+	    Test.ok(30, count==100);
+
+	    // Try to fetch a non-existent key
+	    boolean caught = false;
+	    try {
+		db.fetch("larry!");
+	    } catch ( GdbmException e ) {
+		// TODO: Check the exception was the one we expected?
+		caught = true;
+	    }
+	    Test.ok(40, caught);
+
+	    // Store some very large data
+	    testLongData(db);
+
+	    // Store strings containing non-ASCII characters
+	    final String euroString = "Some funny characters: «¡ æ ø â ß !»";
+	    db.store("high ASCII", euroString);
+	    Test.ok(50, db.fetch("high ASCII").equals(euroString));
+
+	    // Close the database
+	    db.close();
+	    Test.ok(60, true);
+
+	    // Try to read from a database that is closed
+	    caught = false;
+	    try {
+		db.fetch("larry!");
+	    } catch ( Exception e ) {
+		System.out.println("caught: " + e.toString());
+		caught = true;
+	    }
+	    Test.ok(70, caught);
+
+	    // Try to open a non-existent database
+	    caught = false;
+	    try {
+		db = new GdbmFile("/tmp/somenonexistentdatabase.gdbm",
+				  GdbmFile.READER);
+	    } catch ( GdbmException e ) {
+		System.out.println("caught: " + e.toString());
+		caught = true;
+	    }
+	    Test.ok(80, caught);
+
+	    // Open a database read-only
+	    db = new GdbmFile(dbFile, GdbmFile.READER);
+	    db.setKeyPacking(new StringPacking());
+	    db.setValuePacking(new StringPacking());
+	    Test.ok(90);
+
+	    // Try to insert
+	    caught = false;
+	    try {
+		db.store("apple", "crumble");
+	    } catch ( GdbmException e ) {
+		System.out.println("caught: " + e.toString());
+		caught = true;
+	    }
+	    Test.ok(91, caught);
+
+	    // Replace an existing database
+	    db.close();
+	    db = new GdbmFile(dbFile, GdbmFile.NEWDB);
+	    db.setKeyPacking(new StringPacking());
+	    db.setValuePacking(new StringPacking());
+	    Test.ok(100, !db.exists("camel"));
+
+	    // Sync to disk
+	    db.sync();
+	    Test.ok(105, true);
+
+	    // Juggle three databases at once
+	    final String dbFile2 = "/tmp/java2.gdbm";
+	    GdbmFile db2 = new GdbmFile(dbFile2, GdbmFile.NEWDB);
+	    final String dbFile3 = "/tmp/java3.gdbm";
+	    GdbmFile db3 = new GdbmFile(dbFile3, GdbmFile.NEWDB);
+	    Test.ok(110, true);
+
+	    keys = db.keys();
+	    while (keys.hasMoreElements()) {
+		key = (String) keys.nextElement();
+		value = (String) db.fetch(key);
+		db2.store(key.getBytes(), value.getBytes());
+		db3.store(key.getBytes(), value.getBytes());
+	    }
+	    Test.ok(120, true);
+
+	    keys = db2.keys();
+	    found = true;
+	    while (keys.hasMoreElements())
+		found &= db3.exists(keys.nextElement());
+	    Test.ok(130, found);
+
+	    db2.close();
+	    db3.close();
+
+	    Test.ok(140, true);
+
+	    testBigFile(db);
+
+	    db.close();
+	    Test.ok(160, true);
+	} catch (Exception e) {
+	    e.printStackTrace();
+	}
+    }
+}
Index: /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/io/IOUtils.java
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/io/IOUtils.java	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/io/IOUtils.java	(revision 14125)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 1997 by Pharos IP Pty Ltd
+ * All rights reserved.
+ * $Id$
+ */
+
+package au.com.pharos.io;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * Plumbing utilities for manipulating Java IO classes.
+ *
+ * <P>These utilities really ought to be part of the
+ * <CODE>java.io</CODE> package, but they're not.  Since they're
+ * pretty useful, here they are.
+ *
+ * @version $Revision$
+ * @author Martin Pool
+ **/
+public class IOUtils {
+    /** Size of blocks to read during IO. **/
+    static public final int BLOCK_SIZE = 4<<10;
+
+    static public void pumpStream(InputStream inStream,
+				  OutputStream outStream,
+				  int contentLength)
+	 throws IOException
+    {
+	int readBytes = 0;
+	byte[] block = new byte[BLOCK_SIZE];
+	int blockBytes;
+	while (readBytes < contentLength
+	       && (blockBytes = inStream.read(block)) > 0) {
+	    readBytes += blockBytes;
+	    outStream.write(block, 0, blockBytes);
+	}
+    }
+
+    static public int pumpStream(InputStream inStream,
+				 OutputStream outStream)
+	 throws IOException
+    {
+	byte[] block = new byte[BLOCK_SIZE];
+	int blockBytes, readBytes = 0;
+	while ( (blockBytes = inStream.read(block)) > 0 ) {
+	    outStream.write(block, 0, blockBytes);
+	    readBytes += blockBytes;
+	}
+	return readBytes;
+    }
+
+    /** Reads the entire contents of the stream into a
+     * newly-constructed byte array.
+     **/
+    static public byte[] readAll(InputStream inStream)
+	 throws IOException
+    {
+	ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+	pumpStream(inStream, byteStream);
+	byte[] buf = byteStream.toByteArray();
+	byteStream.close();
+	return buf;
+    }
+}
Index: /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/meta/SerializationDumper.java
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/meta/SerializationDumper.java	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/meta/SerializationDumper.java	(revision 14125)
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 1997 Pharos IP Pty Ltd
+ * $Id$
+ * Confidential. All rights reserved.
+ */
+
+package au.com.pharos.meta;
+
+import java.lang.reflect.Field;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamException;
+import java.io.OptionalDataException;
+import java.io.PrintWriter;
+
+/*
+ * TODO: Allow people to specify an input file?
+ * TODO: Allow people to customize the display format?
+ *
+ * FIXME: We should use a custom classloader to load the untrusted
+ * classes under examination and to allow for flexible handling or
+ * tracing as classes are loaded.
+ */
+
+
+/** Java utility to display in a debugging format the contents of a
+ * serialized object stream.
+ *
+ * <P>Usage:
+ * <PRE>
+ *   java au.com.pharos.meta.SerializationDumper <SERFILE
+ * </PRE>
+ *
+ * where SERFILE is the name of the serialization file.
+ *
+ * <P><B>Limitations:</B>
+ *
+ * <OL>
+ *   <P><LI>Values are displayed only for public fields, due to Java
+ *    security restrictions.
+ *   <P><LI>Only top-level objects are dumped.
+ * </OL>
+ *
+ * <P>These are fairly serious restrictions, but SerializationDumper
+ * at least checks that the stream is well-formed, and gives some
+ * indication of what it contains.
+ *
+ * @author Martin Pool
+ * @version $Revision$
+ **/
+public class SerializationDumper {
+    public static void main(String argv[])
+    {
+	try {
+	    ObjectInput in = new ObjectInputStream(System.in);
+	    PrintWriter writer = new PrintWriter(System.out);
+	    SerializationDumper dumper = new SerializationDumper();
+	    dumper.dump(in, writer);
+	    writer.flush();
+	} catch (IOException e) {
+	    e.printStackTrace();
+	}
+    }
+
+
+    /** Dump all objects read from <EM>in</EM> to <EM>out</EM>
+     * in a human-readable debugging form.
+     **/
+    public void dump(ObjectInput in, PrintWriter out)
+	 throws IOException
+    {
+	while (true) {		// exception on eof
+	    Object obj = null;
+	    try {
+		obj = in.readObject();
+		displayObject(obj, out);
+	    }
+	    catch (ClassNotFoundException e) {
+		warning(e, out);
+	    }
+	    catch (OptionalDataException e) {
+		error(e, out);
+		return;
+	    }
+	    catch (ObjectStreamException e) {
+		warning(e, out);
+	    }
+	    catch (EOFException e) {
+		return;
+	    }
+	}
+    }
+
+
+    /** Display an object in human-readable form. **/
+    private void displayObject(Object obj, PrintWriter out)
+	 throws IOException
+    {
+	if (obj == null) {
+	    out.println("(null)");
+	    return;
+	}
+
+	Class cls = obj.getClass();
+
+	// Print the header: the name, hashcode, and string
+	// representation
+	out.println(cls.getName() + "@0x" +
+		    Integer.toHexString(obj.hashCode()) + "{");
+	out.println("\t\"" + obj.toString() + "\"");
+
+	// TODO: Recursive descent of the graph, allowing for circular
+	// structures.
+
+	// Print each field of the object
+	Field[] fields = cls.getDeclaredFields();
+	for (int i = 0; i < fields.length; i++)
+	    displayField(obj, fields[i], out);
+
+	out.println("}");
+    }
+
+
+    /** Display a particular field from an object in human-readable
+      * form.  Fields which are not accessible for security reasons
+      * are noted as such, and the name and type of the field is
+      * still printed. **/
+    private void displayField(Object obj, Field fld, PrintWriter out)
+	 throws IOException
+    {
+	int flags = fld.getModifiers();
+	out.print("\t");
+	out.print(fld.toString() + ": ");
+	try {
+	    Object value = fld.get(obj);
+	    if (value == null) {
+		out.println("(null)");
+	    }
+	    else {
+		out.println(value.getClass().getName() + "@0x" +
+			    Integer.toHexString(value.hashCode()) + ":");
+		out.println("\t\t\"" + value.toString() + "\"");
+	    }
+	} catch (IllegalAccessException e) {
+	    out.println("(not accessible)");
+	}
+    }
+
+
+    /** Display a warning that an exception occurred while dumping
+     * information. **/
+    private void warning(Exception e, PrintWriter out)
+	 throws IOException
+    {
+	out.println("warning: " + e);
+    }
+
+    /** Display an exception that occurred while dumping
+     * information. **/
+    private void error(Exception e, PrintWriter out)
+	 throws IOException
+    {
+	out.println("error: " + e.toString());
+    }
+}
+
Index: /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/meta/ShowClass.java
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/meta/ShowClass.java	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/meta/ShowClass.java	(revision 14125)
@@ -0,0 +1,118 @@
+// This example is from the book "Java in a Nutshell, Second Edition".
+// Written by David Flanagan.  Copyright (c) 1997 O'Reilly & Associates.
+// You may distribute this source code for non-commercial purposes only.
+// You may study, modify, and use this example for any purpose, as long as
+// this notice is retained.  Note that this example is provided "as is",
+// WITHOUT WARRANTY of any kind either expressed or implied.
+
+import java.lang.reflect.*;
+
+/** A program that displays a class synopsis for the named class */
+public class ShowClass {
+  /** The main method.  Print info about the named class */
+  public static void main(String[] args) throws ClassNotFoundException {
+    Class c = Class.forName(args[0]);
+    print_class(c);
+  }
+
+  /** Display the modifiers, name, superclass and interfaces of a class
+   *  or interface. Then go and list all constructors, fields, and methods. */
+  public static void print_class(Class c)
+  {
+    // Print modifiers, type (class or interface), name and superclass.
+    if (c.isInterface()) {
+      // The modifiers will include the "interface" keyword here...
+      System.out.print(Modifier.toString(c.getModifiers()) +  c.getName());
+    }
+    else
+      System.out.print(Modifier.toString(c.getModifiers()) + " class " +
+                       c.getName() +
+                       " extends " + c.getSuperclass().getName());
+
+    // Print interfaces or super-interfaces of the class or interface.
+    Class[] interfaces = c.getInterfaces();
+    if ((interfaces != null) && (interfaces.length > 0)) {
+      if (c.isInterface()) System.out.println(" extends ");
+      else System.out.print(" implements ");
+      for(int i = 0; i < interfaces.length; i++) {
+        if (i > 0) System.out.print(", ");
+        System.out.print(interfaces[i].getName());
+      }
+    }
+
+    System.out.println(" {");            // Begin class member listing.
+
+    // Now look up and display the members of the class.
+    System.out.println(" // Constructors");
+    Constructor[] constructors = c.getDeclaredConstructors();
+    for(int i = 0; i < constructors.length; i++)      // Display constructors.
+      print_method_or_constructor(constructors[i]);
+
+    System.out.println(" // Fields");
+    Field[] fields = c.getDeclaredFields();           // Look up fields.
+    for(int i = 0; i < fields.length; i++)            // Display them.
+      print_field(fields[i]);
+
+    System.out.println(" // Methods");
+    Method[] methods = c.getDeclaredMethods();        // Look up methods.
+    for(int i = 0; i < methods.length; i++)           // Display them.
+      print_method_or_constructor(methods[i]);
+
+    System.out.println("}");             // End class member listing.
+  }
+
+  /** Return the name of an interface or primitive type, handling arrays. */
+  public static String typename(Class t) {
+    String brackets = "";
+    while(t.isArray()) {
+      brackets += "[]";
+      t = t.getComponentType();
+    }
+    return t.getName() + brackets;
+  }
+
+  /** Return a string version of modifiers, handling spaces nicely. */
+  public static String modifiers(int m) {
+    if (m == 0) return "";
+    else return Modifier.toString(m) + " ";
+  }
+
+  /** Print the modifiers, type, and name of a field */
+  public static void print_field(Field f) {
+    System.out.println("  " +
+                       modifiers(f.getModifiers()) +
+                       typename(f.getType()) + " " + f.getName() + ";");
+  }
+
+  /** Print the modifiers, return type, name, parameter types and exception
+   *  type of a method or constructor.  Note the use of the Member interface
+   *  to allow this method to work with both Method and Constructor objects */
+  public static void print_method_or_constructor(Member member) {
+    Class returntype=null, parameters[], exceptions[];
+    if (member instanceof Method) {
+      Method m = (Method) member;
+      returntype = m.getReturnType();
+      parameters = m.getParameterTypes();
+      exceptions = m.getExceptionTypes();
+    } else {
+      Constructor c = (Constructor) member;
+      parameters = c.getParameterTypes();
+      exceptions = c.getExceptionTypes();
+    }
+
+    System.out.print("  " + modifiers(member.getModifiers()) +
+                     ((returntype!=null)? typename(returntype)+" " : "") +
+                     member.getName() + "(");
+    for(int i = 0; i < parameters.length; i++) {
+      if (i > 0) System.out.print(", ");
+      System.out.print(typename(parameters[i]));
+    }
+    System.out.print(")");
+    if (exceptions.length > 0) System.out.print(" throws ");
+    for(int i = 0; i < exceptions.length; i++) {
+      if (i > 0) System.out.print(", ");
+      System.out.print(typename(exceptions[i]));
+    }
+    System.out.println(";");
+  }
+}
Index: /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/packing/NativeStringPacking.java
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/packing/NativeStringPacking.java	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/packing/NativeStringPacking.java	(revision 14125)
@@ -0,0 +1,82 @@
+/*
+ * module: pip/java/packing -- Strategy objects for converting
+ * Java objects to and from stored data.
+ *
+ * Copyright (C) 1997 Pharos IP Pty Ltd
+ * $Id$
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the 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 au.com.pharos.packing;
+
+/** Convert an array of bytes in a Java string without using String
+ * encodings, just using expanding 8-bit bytes to 16-bit chars.
+ *
+ * <P>This will only work for ASCII characters, of course, but for
+ * moving bulk data around it is considerably faster than using
+ * UTF-8 encoding strategies.  Naively compressing Unicode into
+ * 8-bit characters in this manner is deprecated in JDK1.1 to
+ * help ensure that programs are Unicode-safe.
+ *
+ * @author Martin Pool
+ * @version $Revision$
+ *
+ * @see au.com.pharos.packing.Packing
+ * @see au.com.pharos.packing.StringPacking
+ */
+public class NativeStringPacking extends Packing
+{
+    /** Convert an object to an ASCII String representation.
+     *
+     * @return null if obj is null; obj is obj is already a
+     * byte[]; otherwise an native 8-bite encoded version of
+     * obj.toString().
+     **/
+    public byte[] toBytes(final Object obj)
+    {
+	String str;
+	if (obj == null)
+	    return null;
+	else if (obj instanceof byte[])
+	    return (byte[]) obj;
+	else if (obj instanceof String)
+	    str = (String) obj;
+	else
+	    str = obj.toString();
+
+	int len = str.length();
+	byte[] rawArray = new byte[len];
+	str.getBytes(0, len, rawArray, 0);
+	return rawArray;		     
+    }
+
+    /** Convert an array of bytes into a String
+     *
+     * @param raw the raw data to be decoded.
+     *
+     * @return null if <em>raw</em> is null; otherwise a string with the low
+     * 8 bits of each character taken from the corresponding byte in
+     * <em>raw</em>.
+     **/
+    public Object fromBytes(final byte[] raw)
+    {
+	if (raw == null)
+	    return null;
+	else
+	    return new String(raw, 0);
+    }
+}
+    
Index: /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/packing/Packing.java
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/packing/Packing.java	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/packing/Packing.java	(revision 14125)
@@ -0,0 +1,77 @@
+/*
+ * module: pip/java/packing -- Packing strategy objects for converting
+ *           Java objects to and from stored data.
+ * class: Packing -- Abstract strategy class for packing/unpacking data
+ *
+ * $Id$
+ * Copyright (C) 1997 Pharos IP Pty Ltd
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the 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 au.com.pharos.packing;
+
+/** A packing Packing defines a method of converting an object to
+ * and from an array of bytes for storage in a database.
+ *
+ * <P>Generally, each packing Packing should be reflexive: that is,
+ * converting any object to and from an array of bytes should yield
+ * the same object, or an object appropriately equivalent.
+ *
+ * <P>Some Packing subclasses may not be able to pack all
+ * objects, or may not be able to unpack an object from some byte
+ * arrays.  For example, only Strings can safely be stored as string
+ * representations, and not all arrays are valid Java serialization
+ * forms.  In this case, the Packing object should throw an
+ * <code>IllegalArgumentException</code> from <code>toBytes()</code>
+ * or <code>toBytes()</code>.
+ *
+ * <P>In both cases, null references should be passed through
+ * unchanged.
+ *
+ * <P>Example:
+ * <PRE>
+ *    Packing strategy = new StringPacking();
+ *    byte[] raw = strategy.toBytes("Hello world");
+ *    ... store and retrieve raw[]
+ *    String result = (String) strategy.fromBytes(raw)
+ * </PRE>
+ *
+ *
+ * @see au.com.pharos.packing.StringPacking
+ * @see au.com.pharos.packing.NativeStringPacking
+ * @see au.com.pharos.packing.RawPacking
+ * @see au.com.pharos.packing.SerializationPacking
+ *
+ * @version $Revision$
+ * @author Martin Pool
+ **/
+public abstract class Packing {
+    /** Convert an object to an array of bytes. **/
+    public abstract byte[] toBytes(Object obj) throws IllegalArgumentException;
+
+    /** Reconstitute an array of bytes into an object. **/
+    public abstract Object fromBytes(byte[] raw) throws IllegalArgumentException;
+
+    /** Helper function that generates an IllegalArgumentException */
+    protected IllegalArgumentException cantConvert(Object obj) {
+	return new IllegalArgumentException
+	    ("Can't pack object \"" + obj.toString() +
+	     "\" (" + obj.getClass().toString() + ")" + 
+	     "\n\tusing strategy " + this.toString());
+    }
+}
+
+    
Index: /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/packing/QuotedVectorPacking.java
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/packing/QuotedVectorPacking.java	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/packing/QuotedVectorPacking.java	(revision 14125)
@@ -0,0 +1,187 @@
+/*
+ * module: pip/java/packing -- Strategy objects for converting
+ *         Java objects to and from stored data.
+ * class:  QuotedVectorPacking -- Vectors of Strings packed in a Perl-
+ *         style format
+ *
+ * Copyright (C) 1997 Pharos IP Pty Ltd
+ * $Id$
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the 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 au.com.pharos.packing;
+
+import java.util.Vector;
+
+// FIXME: Escape bad characters! -- mbp
+// TODO: Write a more formal definition of the encoding system
+// TODO: More documentation
+
+// XXX: Perhaps the strategy for encoding characters should be in a
+// separate class used by this class?  They would have to
+// interact to make sure that separator chatacters were decoded
+// properly.  Probably not worth worrying about, as this class
+// is only a compatibility measure in any case.
+
+/** Stores Vectors of strings, packed into a single string, as used by
+ * some Perl code.  The encoding format is similar to that used in
+ * Unix databases like
+ * <A HREF="file:/etc/passwd/"><CODE>/etc/passwd</CODE></A>, except that
+ * it uses escape sequences to represent characters that would
+ * normally not be allowed.
+ *
+ * <P>The strings within the vector are separated by separator characters,
+ * which default to colons.
+ *
+ * <P>The resulting packed string is UTF encoded after escaping
+ * control-characters, so non-ASCII characters should be passed through
+ * unchanged.
+ *
+ * <P>Certain characters are escaped as quoted-printable strings.
+ * These characters include colon, equals, and escape characters.  The
+ * encoding accepts and interprets any hex escape when reading data.
+ *
+ * <P>If any elements of the vector are null, they are stored as empty
+ * strings.  On unpacking, empty strings are returned as such.
+ *
+ * <P>An example of a vector encoded in this manner is:
+ * <BLOCKQUOTE>
+ * <PRE>oC7okz059wGnQ:vf:Peter Barnes%2c Pharos Business Solutions</PRE>
+ * </BLOCKQUOTE>
+ *
+ * @author Martin Pool
+ * @version $Revision$ $Date$
+ *
+ * @see java.util.Vector
+ **/
+public class QuotedVectorPacking extends Packing
+implements java.io.Serializable
+{
+    private char hexEscape;
+    private char separator;
+    
+    /** Constructs a QuotedVectorPacking using the default separator
+     * character ':' and escape character '%'.
+     **/
+    public QuotedVectorPacking() {
+	this('%', ':');
+    }
+
+
+    /** Constructs a QuotedVectorPacking with specified separator and
+     * hex-escape characters.
+     *
+     * @param hexEscape the character used to begin a three-character
+     * hex escape
+     *
+     * @param separator the character used to separate elements in the
+     * vector.
+     **/
+    public QuotedVectorPacking(char hexEscape, char separator) {
+	if (hexEscape == separator)
+	    throw new IllegalArgumentException
+		("hexEscape and separator characters are the same");
+	this.hexEscape = hexEscape;
+	this.separator = separator;
+    }
+    
+    
+    /** Convert a Vector of Strings to a QuotedVector represented as an
+     * array of bytes.
+     *
+     * @param obj the Vector to encode; or null.
+     * 
+     * @returns an array of bytes containing a packed representation of
+     * <EM>obj</EM>; or null if <EM>obj</EM> is null.
+     *
+     * @exception java.lang.ClassCastException if obj is not a Vector
+     * or null; or if any element of <EM>obj</EM> is not a String or
+     * null.
+     **/
+    public byte[] toBytes(Object obj)
+    {
+	if (obj == null)
+	    return null;
+	Vector vec = (Vector) obj;
+	StringBuffer sb = new StringBuffer();
+	Object elem;
+	for (int i = 0; i < vec.size(); i++) {
+	    if (i > 0)
+		sb.append(separator);
+	    elem = vec.elementAt(i);
+	    sb.append((elem == null) ? "" : encodeString((String) elem));
+	}
+	return sb.toString().getBytes();
+    }
+
+
+
+    /** Perform hex-escapes on a string.
+     * @returns <EM>from</EM> encoded as a quoted-printable string
+     **/
+    private String encodeString(String from) {
+	StringBuffer buf = new StringBuffer(from.length());
+	char[] chars = from.toCharArray();
+	for (int i = 0; i < chars.length; i++) {
+	    char ch = chars[i];
+	    if (ch == separator
+		|| ch == hexEscape
+		|| Character.isISOControl(ch)
+		|| (ch != ' ' && ch != '\t' && Character.isWhitespace(ch)))
+		{
+		    buf.append(hexEscape);
+		    // XXX: This will truncate high Unicode characters, but I
+		    // don't know what else we can do with them. -- mbp
+		    buf.append(Character.forDigit((ch>>4) & 0xf, 16));
+		    buf.append(Character.forDigit(ch      & 0xf, 16));
+		} else {
+		    buf.append(ch);
+		}
+	}
+	return buf.toString();
+    }
+    
+    
+
+    /** Interprets <em>raw</em> as a packed quoted Vector, and
+     * returns the unpacked Vector of strings. */
+    public Object fromBytes(byte[] raw)
+    {
+	if (raw == null)
+	    return null;
+	
+	Vector result = new Vector();
+	StringBuffer sb = new StringBuffer();
+	for (int i = 0; i < raw.length; i++) {
+	    char ch = (char) raw[i];
+	    if (ch == separator) {
+		result.addElement(sb.toString());
+		sb.setLength(0);
+	    } else if (ch == hexEscape && i < (raw.length - 2)) {
+		byte[] hexBytes = new byte[2];
+		hexBytes[0] = raw[++i];
+		hexBytes[1] = raw[++i];
+		String hex = new String(hexBytes);
+		ch = (char)Integer.parseInt(hex, 16);
+		sb.append(ch);
+	    } else {
+		sb.append(ch);
+	    }
+	}
+	result.addElement(sb.toString());
+	return result;
+    }
+}
Index: /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/packing/RawPacking.java
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/packing/RawPacking.java	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/packing/RawPacking.java	(revision 14125)
@@ -0,0 +1,60 @@
+/*
+ * module: pip/java/packing -- Strategy objects for converting
+ * Java objects to and from stored data.
+ *
+ * Copyright (C) 1997 Pharos IP Pty Ltd
+ * $Id$
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the 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 au.com.pharos.packing;
+
+/** A packing strategy which stores only raw arrays of bytes.  Other
+ * objects cannot be stored using this strategy.
+ *
+ * @author Martin Pool
+ * @version $Revision$
+ **/
+public class RawPacking extends Packing implements java.io.Serializable
+{
+    /** Perform the trivial packing case, casting an array of bytes
+     * into the same.
+     *
+     * @throw IllegalArgumentException if <em>obj</em> is neith null nor
+     * an array of bytes.
+     */
+    public byte[] toBytes(Object obj) throws IllegalArgumentException
+    {
+	if (obj == null)
+	    return null;
+	else if (obj instanceof byte[])
+	    return (byte[]) obj;
+	else
+	    throw cantConvert(obj);
+    }
+
+    /** Performs the trivial unpacking case of returning <em>raw</em>
+     * untouched.
+     *
+     * @return either null or <em>raw</em>; always assignable to
+     * <code>byte[]</code>
+     **/
+    public Object fromBytes(byte[] raw)
+    {
+	return raw;
+    }
+}
+    
Index: /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/packing/SerializationPacking.java
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/packing/SerializationPacking.java	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/packing/SerializationPacking.java	(revision 14125)
@@ -0,0 +1,100 @@
+/*
+ * class: SerializationPacking -- Store an object as serialized data
+ *
+ * Copyright (C) 1997 Pharos IP Pty Ltd
+ * $Id$
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the 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 au.com.pharos.packing;
+
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ObjectInputStream;
+import java.io.IOException;
+
+/** A packing strategy which stores and retrieves objects using
+ * <a href="http://www.javasoft.com/products/jdk/1.1/docs/guide/serialization/index.html">Java serialization</a>.
+ *
+ * @version $Revision$
+ * @author Martin Pool
+ * @see au.com.pharos.packing.Packing
+ **/
+public class SerializationPacking extends Packing
+implements java.io.Serializable
+{
+    /** Convert an object to a Java serialization format.
+     *
+     * @returns a buffer containing a a serialized representation of <em>obj</em>;
+     * or null if <em>obj</em> if null
+     * @exception IllegalArgumentException if <em>obj</em> (or any object
+     * referred to by <em>obj</em>) cannot be serialized
+     **/
+    public byte[] toBytes(Object obj) throws IllegalArgumentException
+    {
+	if (obj == null)
+	    return null;
+
+	// Serialize via a stream into a buffer
+	ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+	try {
+	    ObjectOutputStream objStream = new ObjectOutputStream(byteStream);
+	    objStream.writeObject(obj);
+	    // Don't close the stream, or you will lose the byte array
+	    objStream.flush();
+	} catch (IOException e) {
+	    throw new IllegalArgumentException("IOException during serialization: " +
+					       e.toString());
+	}
+
+	return byteStream.toByteArray();
+    }
+
+    /** Interprets <em>raw</em> as a Java serialization stream, and
+     * returns <B>the first</B> object read from that stream.
+     *
+     * <P><B>Note:</B>There is currently no means by which any later
+     * objects in the can be retrieved: it is assumed that the object
+     * written to the buffer contains references to all the
+     * information required.  This is consistent with the fact that
+     * toBytes() stores only a single object, so this packing strategy
+     * is completely reversable.
+     **/
+    // FIXME: Is the correct word 'reversable', 'reflexive', or
+    // something else?  -- mbp@pharos.com.au
+    public Object fromBytes(byte[] raw)
+    {
+	if (raw == null)
+	    return null;
+
+	Object obj;
+	try {
+	    ByteArrayInputStream byteStream = new ByteArrayInputStream(raw);
+	    ObjectInputStream objStream = new ObjectInputStream(byteStream);
+	    obj = objStream.readObject();
+	    objStream.close();
+	} catch (IOException e) {
+	    throw new IllegalArgumentException("Exception during deserialization: " +
+					       e.toString());
+	} catch (ClassNotFoundException e) {
+	    throw new IllegalArgumentException("Exception during deserialization: " +
+					       e.toString());
+	}	    
+	return obj;
+    }
+}
+    
Index: /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/packing/StringPacking.java
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/packing/StringPacking.java	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/packing/StringPacking.java	(revision 14125)
@@ -0,0 +1,85 @@
+/*
+ * module: pip/java/packing -- Strategy objects for converting
+ * Java objects to and from stored data.
+ *
+ * Copyright (C) 1997 Pharos IP Pty Ltd
+ * $Id$
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the 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 au.com.pharos.packing;
+
+/** StringPacking converts Java Strings to and from byte arrays
+ * using the default UTF-8 encoding.
+ *
+ * <P>For strings containing only ASCII-7 characters, this is
+ * equivalent to <code>NativeStringPacking</code> but probably
+ * somewhat slower.  However, it will safely handle non-ASCII
+ * characters, or unusual locales.
+ *
+ * @see au.com.pharos.packing.Packing
+ * @see au.com.pharos.packing.NativeStringPacking
+ **/
+public class StringPacking extends Packing
+implements java.io.Serializable
+{
+    /** Convert a String to an array of bytes using Java's default
+     * encoding.
+     *
+     * <P>If <em>obj</em> is not a String, array of bytes, or null
+     * then it's <code>toString()</code> method is called first to
+     * convert it to an array of bytes.  This will lose information in
+     * many cases.
+     *
+     * @param obj The object to convert.
+     *
+     * @return <em>obj</em> converted to an array of bytes; or null if
+     * <em>obj</em> is null.
+     **/
+    public byte[] toBytes(Object obj)
+    {
+	if (obj == null)
+	    return null;
+	else if (obj instanceof byte[])
+	    return (byte[]) obj;
+	else if (obj instanceof String)
+	    return ((String) obj).getBytes();
+	else
+	    return obj.toString().getBytes();
+    }
+
+    /** Decode an array of bytes using the default String encoding.
+     *
+     * @param raw An array of bytes to decode.
+     *
+     * @return A String representation of <em>raw</em>; or null if
+     * <em>raw</em> is null.
+     **/     
+    public Object fromBytes(byte[] raw)
+    {
+	if (raw == null)
+	    return null;
+	else {
+	    try{
+	    return new String(raw, "UTF-8");
+	    } catch (Exception e) {
+		System.err.println("String Packing:encoding not supported");
+		return new String(raw);
+	    }
+	}
+    }
+}
+    
Index: /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/packing/TestQuotedVectorPacking.java
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/packing/TestQuotedVectorPacking.java	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/packing/TestQuotedVectorPacking.java	(revision 14125)
@@ -0,0 +1,84 @@
+/*
+ * module: pip/java/packing -- Strategy objects for converting
+ *         Java objects to and from stored data.
+ * class:  TestQuotedVectorPacking -- Test harness for QuotedVectorPacking
+ *
+ * Copyright (C) 1997 Pharos IP Pty Ltd
+ * $Id$
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the 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 au.com.pharos.packing;
+
+import java.util.Vector;
+
+// TODO: Perhaps make this into a more general-purpose test harness
+// for testing any Packing strategy? -- mbp 19971021
+
+/** Test harness for the QuotedVectorPacking strategy class.
+ *
+ * <P><B>Usage:</B>
+ * <UL><P><CODE>java TestQuotedVectorPacking -[de] ARGS</CODE><UL>
+ *
+ * <P><B>Options</B>
+ * <DL>
+ *   <P><DT><CODE>-d</CODE><DD>Print the results of decoding
+ *      the each of the command-
+ *      line arguments as QuotedVectorPacking encoding strings
+ *
+ *   <P><DT><CODE>-e</CODE><DD>Print the results of encoding
+ *      a vector containing
+ *      all of the command-line arguments 
+ * </DL>
+ *
+ * @author Martin Pool
+ * @version $Revision$ $Date$
+ **/
+public class TestQuotedVectorPacking {
+    private TestQuotedVectorPacking() {}
+    
+    public static void main(String[] argv) {
+	Packing strat = new QuotedVectorPacking();
+	final String usage = "usage: TestQuotedVectorPacking -[ed] ARGS";
+
+	if (argv.length == 0) {
+	    System.err.println(usage);
+	    return;
+	}
+	
+	if (argv[0].equals("-e")) {
+	    Vector encode = new Vector(argv.length - 1);
+	    for (int i = 1; i < argv.length; i++) {
+		System.out.println(argv[i]);
+		encode.addElement(argv[i]);
+	    }
+	    byte[] packed = strat.toBytes(encode);
+	    System.out.print("\t");
+	    System.out.println(new String(packed));
+	} else if (argv[0].equals("-d")) {
+	    for (int i = 1; i < argv.length; i++) {
+		Vector decode = (Vector) strat.fromBytes(argv[i].getBytes());
+		System.out.println(argv[i]);
+		for (int j = 0; j < decode.size(); j++) {
+		    System.out.print("\t");
+		    System.out.println(decode.elementAt(j));
+		}
+	    }
+	} else {
+	    System.err.println(usage);
+	}
+    }
+}
Index: /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/test/Test.java
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/test/Test.java	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/test/Test.java	(revision 14125)
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 1997 Pharos IP Pty Ltd
+ * $Id$
+ * $Source$
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the 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 au.com.pharos.test;
+
+/** Utilities for automated testing.  This class contains only static
+ * functions and should not be instantiated.
+ *
+ * @author Martin Pool
+ * @version $Revision$ $Date$
+ **/
+// TODO: Somehow automatically generate sequence numbers, or perhaps use
+// strings to report progress
+public class Test {
+    // Don't instantiate
+    private Test() {}
+
+    static int nPassed, nFailed;
+
+    /** Register that a particular test executed successfully, and
+     * output a success or failure message.
+     *
+     * @param number test sequence number
+     **/
+    static public void ok(int no) {
+	ok(no, true);
+    }
+
+    /** Register the result of a test, and output a success or failure
+     * message.
+     *
+     * @param number test sequence number
+     * @param result whether the test was successful or not
+     */
+    static public void ok(int number, boolean passed) {
+	if (passed) {
+	    nPassed++;
+	}
+	else {
+	    System.out.print("not ");
+	    nFailed++;
+	}
+	System.out.print("ok " + number + "\n");
+    }
+
+    /**
+     * Print a summary of test results.
+     **/
+    static public void summary() {
+	System.out.print("test summary: " + nPassed + " passed, " +
+			 nFailed + " failed");
+    }
+}
+    
Index: /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/util/StringOps.java
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/util/StringOps.java	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/util/StringOps.java	(revision 14125)
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 1997 by Pharos IP Pty Ltd
+ * Confidential.  All rights reserved.
+ * $Id$
+ * $Source$
+ *
+ * ``No strings attached.''
+ */
+
+package au.com.pharos.util;
+
+/**
+ * Mixed bag of string manipulation functions.  It would be nice if
+ * some of these were in <CODE>java.lang.String</CODE>, but since
+ * they're not, they're implemented as static functions within this
+ * class.
+ *
+ * Typical use:
+ * <PRE>
+ * String foo = "some string"
+ * int cnt = StringOps.countOccurrences(foo, 's');
+ * // --> cnt == 2
+ * </PRE>
+ *
+ * @author Martin Pool
+ * @version $Revision$, $Date$
+ **/
+public class StringOps
+{
+    /** This class contains only static public functions. **/
+    private StringOps() { ; }
+
+    /** Count the number of occurences of a character in a
+     * string.
+     *
+     * @param needle the character to search
+     * @param haystack string to be searched
+     *
+     * @return 0 if <EM>needle</EM> does not occur in <EM>haystack</EM>;
+     * or a positive number indicating the number of occurrences
+     **/
+    static public int countOccurrences(String haystack, char needle)
+    {
+	byte[] hay = haystack.getBytes();
+	int count = 0;
+	for (int i = 0; i < hay.length; i++)
+	    if (hay[i] == needle)
+		count++;
+	return count;
+    }
+}
Index: /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/util/test/StringOpsTest.java
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/util/test/StringOpsTest.java	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/au/com/pharos/util/test/StringOpsTest.java	(revision 14125)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 1997 by Pharos IP Pty Ltd
+ * Confidential.  All rights reserved.
+ * $Id$
+ * $Source$
+ */
+
+package au.com.pharos.util.test;
+
+import au.com.pharos.test.Test;
+
+import au.com.pharos.util.StringOps;
+
+/**
+ * Test harness for <CODE>au.com.pharos.util.StringOps</CODE>
+ *
+ * @author Martin Pool
+ * @version $Revision$ $Date$
+ **/
+public class StringOpsTest
+{
+    static public void main(String[] args)
+    {
+	new StringOpsTest().run();
+    }
+
+    public void run()
+    {
+	try {
+	    testCountOccurrences();
+	}
+	finally {
+	    Test.summary();
+	}
+    }
+
+    public void testCountOccurrences()
+    {
+	// Simple tests of countOccurences(String, char)
+	Test.ok(100, ( StringOps.countOccurrences("hello world", 'z') == 0) );
+	Test.ok(110, ( StringOps.countOccurrences("zhello world", 'z') == 1) );
+	Test.ok(120, ( StringOps.countOccurrences("hello worldz", 'z') == 1) );
+	Test.ok(130, ( StringOps.countOccurrences("z", 'z') == 1) );
+	Test.ok(140, ( StringOps.countOccurrences("zzz", 'z') == 3) );
+	Test.ok(150, ( StringOps.countOccurrences("0z0z0z", 'z') == 3) );
+	Test.ok(160, ( StringOps.countOccurrences("\0z\0z\0z", '\0') == 3) );
+    }
+}
Index: /greenstone3/trunk/src/packages/javagdbm/java/winMake.bat
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/java/winMake.bat	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/java/winMake.bat	(revision 14125)
@@ -0,0 +1,45 @@
+@echo off
+
+set JAVAGDBMHOME=..
+
+rem ---- Where to put class files ----
+set JAVACLASSDIR=classes
+
+rem ---- Name and location of java programs ----
+set JAVAC="%JAVA_HOME%\bin\javac"
+set JAVAH="%JAVA_HOME%\bin\javah"
+set JAVA="%JAVA_HOME%\bin\java"
+set JAVADOC="%JAVA_HOME%\bin\javadoc"
+set JAR="%JAVA_HOME%\bin\jar"
+
+set JAVACOPTIONS= -deprecation -g -O
+
+
+if ""%1"" == """" goto compile
+if ""%1"" == ""compile"" goto compile
+if ""%1"" == ""install"" goto install
+if ""%1"" == ""clean"" goto clean
+
+:unknown
+	echo Error: Unrecognized argument %1.
+	goto done
+
+:compile
+	if not exist %JAVACLASSDIR% mkdir %JAVACLASSDIR%
+	echo Compiling...
+        %JAVAC% -d %JAVACLASSDIR% %JAVACOPTIONS%  au\com\pharos\gdbm\*.java au\com\pharos\io\*.java au\com\pharos\meta\*.java au\com\pharos\packing\*.java au\com\pharos\test\*.java au\com\pharos\util\*.java
+        %JAVAH% -classpath %JAVACLASSDIR% -o %JAVAGDBMHOME%\jni\GdbmFile.h au.com.pharos.gdbm.GdbmFile
+        %JAR% cf %JAVAGDBMHOME%\javagdbm.jar -C %JAVACLASSDIR% au
+	goto done
+
+:install
+	goto done
+
+:clean
+	echo Cleaning up...
+	if exist %JAVACLASSDIR% rmdir /S /Q %JAVACLASSDIR%
+        if exist %JAVAGDBMHOME%\javagdbm.jar del %JAVAGDBMHOME%\javagdbm.jar 
+        if exist %JAVAGDBMHOME%\jni\GdbmFile.h del %JAVAGDBMHOME%\jni\GdbmFile.h 
+	goto done
+
+:done
Index: /greenstone3/trunk/src/packages/javagdbm/jni/GdbmFile.h
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/jni/GdbmFile.h	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/jni/GdbmFile.h	(revision 14125)
@@ -0,0 +1,119 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class au_com_pharos_gdbm_GdbmFile */
+
+#ifndef _Included_au_com_pharos_gdbm_GdbmFile
+#define _Included_au_com_pharos_gdbm_GdbmFile
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef au_com_pharos_gdbm_GdbmFile_READER
+#define au_com_pharos_gdbm_GdbmFile_READER 0L
+#undef au_com_pharos_gdbm_GdbmFile_WRITER
+#define au_com_pharos_gdbm_GdbmFile_WRITER 1L
+#undef au_com_pharos_gdbm_GdbmFile_WRCREAT
+#define au_com_pharos_gdbm_GdbmFile_WRCREAT 2L
+#undef au_com_pharos_gdbm_GdbmFile_NEWDB
+#define au_com_pharos_gdbm_GdbmFile_NEWDB 3L
+#undef au_com_pharos_gdbm_GdbmFile_FAST
+#define au_com_pharos_gdbm_GdbmFile_FAST 16L
+/*
+ * Class:     au_com_pharos_gdbm_GdbmFile
+ * Method:    gdbm_open
+ * Signature: (Ljava/lang/String;I)J
+ */
+JNIEXPORT jlong JNICALL Java_au_com_pharos_gdbm_GdbmFile_gdbm_1open
+  (JNIEnv *, jobject, jstring, jint);
+
+/*
+ * Class:     au_com_pharos_gdbm_GdbmFile
+ * Method:    gdbm_close
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_au_com_pharos_gdbm_GdbmFile_gdbm_1close
+  (JNIEnv *, jobject, jlong);
+
+/*
+ * Class:     au_com_pharos_gdbm_GdbmFile
+ * Method:    gdbm_store
+ * Signature: (J[B[BZ)V
+ */
+JNIEXPORT void JNICALL Java_au_com_pharos_gdbm_GdbmFile_gdbm_1store
+  (JNIEnv *, jobject, jlong, jbyteArray, jbyteArray, jboolean);
+
+/*
+ * Class:     au_com_pharos_gdbm_GdbmFile
+ * Method:    gdbm_fetch
+ * Signature: (J[B)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_au_com_pharos_gdbm_GdbmFile_gdbm_1fetch
+  (JNIEnv *, jobject, jlong, jbyteArray);
+
+/*
+ * Class:     au_com_pharos_gdbm_GdbmFile
+ * Method:    gdbm_exists
+ * Signature: (J[B)Z
+ */
+JNIEXPORT jboolean JNICALL Java_au_com_pharos_gdbm_GdbmFile_gdbm_1exists
+  (JNIEnv *, jobject, jlong, jbyteArray);
+
+/*
+ * Class:     au_com_pharos_gdbm_GdbmFile
+ * Method:    gdbm_delete
+ * Signature: (J[B)V
+ */
+JNIEXPORT void JNICALL Java_au_com_pharos_gdbm_GdbmFile_gdbm_1delete
+  (JNIEnv *, jobject, jlong, jbyteArray);
+
+/*
+ * Class:     au_com_pharos_gdbm_GdbmFile
+ * Method:    gdbm_firstkey
+ * Signature: (J)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_au_com_pharos_gdbm_GdbmFile_gdbm_1firstkey
+  (JNIEnv *, jobject, jlong);
+
+/*
+ * Class:     au_com_pharos_gdbm_GdbmFile
+ * Method:    gdbm_nextkey
+ * Signature: (J[B)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_au_com_pharos_gdbm_GdbmFile_gdbm_1nextkey
+  (JNIEnv *, jobject, jlong, jbyteArray);
+
+/*
+ * Class:     au_com_pharos_gdbm_GdbmFile
+ * Method:    gdbm_getversion
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_au_com_pharos_gdbm_GdbmFile_gdbm_1getversion
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     au_com_pharos_gdbm_GdbmFile
+ * Method:    gdbm_wrapperVersion
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_au_com_pharos_gdbm_GdbmFile_gdbm_1wrapperVersion
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     au_com_pharos_gdbm_GdbmFile
+ * Method:    gdbm_reorganize
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_au_com_pharos_gdbm_GdbmFile_gdbm_1reorganize
+  (JNIEnv *, jobject, jlong);
+
+/*
+ * Class:     au_com_pharos_gdbm_GdbmFile
+ * Method:    gdbm_sync
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_au_com_pharos_gdbm_GdbmFile_gdbm_1sync
+  (JNIEnv *, jobject, jlong);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /greenstone3/trunk/src/packages/javagdbm/jni/Makefile.in
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/jni/Makefile.in	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/jni/Makefile.in	(revision 14125)
@@ -0,0 +1,63 @@
+# Makefile for the native parts of the au.com.pharos.gdbm
+# Java package.
+# Modified by kjdon 2005
+
+# Copyright (C) 1997 by Pharos IP Pty Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+#srcdir=@srcdir@
+libdir=@libdir@
+
+CC=@CC@
+CFLAGS=-c @CFLAGS@ $(INC) -DWRAPPER_VERSION=\"$(WRAPPER_VERSION)\" 
+#PKG=@PKG@
+GDBM_LIBS=@GDBM_LIBPATH@ -lgdbm
+LIBS= $(GDBM_LIBS) @LIBS@
+LDFLAGS = @LDFLAGS@
+JNIFLAGS=@JNIFLAGS@
+JNISUFFIX=@JNISUFFIX@
+JNIINC=@JNIINC@
+INC=-I. -I$(JAVA_HOME)/include @GDBM_INCLUDE@ @JNIINC@
+
+
+# TODO: Build versioned shared libraries?
+
+# TODO: Build shared libraries in a way that will work on different
+# platforms -- mbp
+
+WRAPPER_VERSION=0005
+NATIVE_LIB=libgdbmjava.$(JNISUFFIX)
+
+all: $(NATIVE_LIB)
+
+$(NATIVE_LIB): GdbmFile.h gdbmjava.o Makefile
+	$(CC) $(LDFLAGS) $(JNIFLAGS) -o $(NATIVE_LIB) gdbmjava.o $(LIBS)
+
+gdbmjava.o: gdbmjava.c	
+	$(CC) $(INC) $(CFLAGS) $?
+
+# no easy way to tell if a class file has changed or not
+#GdbmFile.h: 
+#	$(javah) -o GdbmFile.h -jni $(PKG).GdbmFile 
+
+clean:	
+	rm -f  *.o $(NATIVE_LIB) 
+
+distclean: clean
+	rm -f Makefile
+
+install: 
+	cp $(NATIVE_LIB) $(libdir)/
Index: /greenstone3/trunk/src/packages/javagdbm/jni/gdbmjava.c
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/jni/gdbmjava.c	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/jni/gdbmjava.c	(revision 14125)
@@ -0,0 +1,476 @@
+/*
+ * module: pip/jni/gdbm -- A Java interface to the GDBM library
+ * file:   gdbmjava.c -- Native parts of the au.com.pharos.gdbm.GdbmFile
+ *             Java class
+ *
+ * Copyright (C) 1997 Pharos IP Pty Ltd
+ *
+ * $Id$ 
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the 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 ON MEMORY MANAGEMENT: GDBM always mallocs memory and expects
+ * the caller to free it.  Java requires native functions to interact
+ * with it to lock and unlock buffers. */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined (__WIN32__)
+#include <gdbmdefs.h>
+#include <gdbmerrno.h>
+#define GDBM_FILE gdbm_file_info *
+extern char* gdbm_version;
+#else
+#include <gdbm.h>
+#endif
+
+#include <jni.h>
+
+#include <GdbmFile.h>
+
+#ifdef DEBUG
+#define ASSERT(x) if (!(x)) { \
+  fprintf(stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
+  abort(); }
+#else /* !DEBUG */
+#define ASSERT(x) 
+#endif /* !DEBUG */
+
+/* The Java class within which the native methods are declared */
+#define JAVA_CLASS "au.com.pharos.gdbm.GdbmFile"
+
+#define NULL_PTR_EXCEPTION(env) nullPtrException(env, __FILE__, __LINE__)
+#define GDBM_EXCEPTION(env) gdbmException(env, __FILE__, __LINE__)
+
+#define CHECK_NOT_NULL(ptr, env) if (!ptr) { NULL_PTR_EXCEPTION(env); return 0; }
+#define CHECK_NOT_NULL_VOID(ptr, env) if (!ptr) { NULL_PTR_EXCEPTION(env); return; }
+
+void gdbmException(JNIEnv *env, const char *file, int line);
+void nullPtrException(JNIEnv *env, const char *file, int line);
+
+void releaseArray(JNIEnv *env, jbyteArray array, datum *fromDatum);
+void releaseArrayAbort(JNIEnv *env, jbyteArray array, datum *fromDatum);
+int arrayToDatum(JNIEnv *env, jbyteArray fromArray, datum *toDatum);
+jbyteArray datumToArray(JNIEnv *env, datum *fromDatum);
+
+/* Convert between a jlong and a void ptr using a well-defined cast.
+ * (Casting between a pointer and an integer of different sizes spooks
+ * both gcc and mbp. */
+#if (SIZEOF_VOID_P == SIZEOF_LONG)
+#  define DBF_TO_JLONG(x) ((jlong)((long) x))
+#  define JLONG_TO_DBF(x) ((GDBM_FILE)((long) x))
+#elif (SIZEOF_VOID_P == SIZEOF_INT)
+#  define DBF_TO_JLONG(x) ((jlong)((int) (x)))
+#  define JLONG_TO_DBF(x) ((GDBM_FILE)((int) (x)))
+#else
+#  define DBF_TO_JLONG(x) ((jlong)(x))
+#  define JLONG_TO_DBF(x) ((GDBM_FILE)(x))
+#endif
+
+
+JNIEXPORT jlong JNICALL 
+Java_au_com_pharos_gdbm_GdbmFile_gdbm_1open
+    (JNIEnv *env, jobject obj, jstring fileName, jint flags)
+{
+    GDBM_FILE dbf;
+    const char *utfFileName;
+   
+    utfFileName = (*env)->GetStringUTFChars(env, fileName, 0);
+    if (!utfFileName) 
+	return 0;
+    
+    setbuf(stderr, 0);
+   
+    /* XXX: Should we let the caller specify the file mode?  I think
+     * not -- Java is above the level of octal file modes. [mbp] */
+    /* Couldn't get it to work properly on Windows without the 0 here - 
+       wouldn't allow mulitple READs on a single file [kjdon] */
+#if defined (__WIN32__) 
+    dbf = gdbm_open((char *) utfFileName, 0, flags, 0660, NULL, 0);
+#else
+    dbf = gdbm_open((char *) utfFileName, 0, flags, 0660, NULL);
+#endif
+    if (utfFileName)
+	(*env)->ReleaseStringUTFChars(env, fileName, utfFileName);
+
+    if (!dbf) {
+	GDBM_EXCEPTION(env);
+	return 0;
+    }	
+   
+    return DBF_TO_JLONG(dbf);
+}
+
+
+
+
+
+JNIEXPORT jbyteArray JNICALL 
+Java_au_com_pharos_gdbm_GdbmFile_gdbm_1firstkey
+(JNIEnv *env, jobject obj, jlong dbf)
+{
+    datum	keyDatum;
+    jbyteArray 	keyArray;
+
+    CHECK_NOT_NULL(dbf, env);
+
+    keyDatum = gdbm_firstkey(JLONG_TO_DBF(dbf));
+    if ( gdbm_errno != GDBM_NO_ERROR ) {
+	GDBM_EXCEPTION(env);
+	return 0;
+    }
+    if ( !keyDatum.dptr )
+	return 0;
+
+    keyArray = datumToArray(env, &keyDatum);
+    free(keyDatum.dptr); 
+
+    return keyArray;
+}
+
+
+
+
+
+JNIEXPORT jbyteArray JNICALL 
+Java_au_com_pharos_gdbm_GdbmFile_gdbm_1nextkey
+(JNIEnv *env, jobject this, jlong dbf, jbyteArray keyArray)
+{
+    datum	keyDatum;
+    datum	nextDatum;
+    jbyteArray	nextArray;
+
+    CHECK_NOT_NULL(dbf, env);
+
+    if (!arrayToDatum(env, keyArray, &keyDatum)) {
+	NULL_PTR_EXCEPTION(env);
+	return 0;
+    }
+    
+    nextDatum = gdbm_nextkey(JLONG_TO_DBF(dbf), keyDatum);
+    releaseArrayAbort(env, keyArray, &keyDatum);
+
+    if ( gdbm_errno != GDBM_NO_ERROR ) {
+	GDBM_EXCEPTION(env);
+	return 0;
+    }
+    if ( !nextDatum.dptr )
+	return 0;
+
+    nextArray = datumToArray(env, &nextDatum);
+    free(nextDatum.dptr);
+    
+    return nextArray;
+}
+
+
+
+
+
+
+JNIEXPORT jbyteArray JNICALL 
+Java_au_com_pharos_gdbm_GdbmFile_gdbm_1fetch
+  (JNIEnv *env, jobject this, jlong dbf, jbyteArray keyArray)
+{
+    datum 	keyDatum;
+    datum 	valueDatum;
+    jbyteArray	valueArray;
+
+    CHECK_NOT_NULL(dbf, env);
+
+    if (!arrayToDatum(env, keyArray, &keyDatum)) {
+	NULL_PTR_EXCEPTION(env);
+	return 0;
+    }
+
+    valueDatum = gdbm_fetch(JLONG_TO_DBF(dbf), keyDatum);
+    releaseArrayAbort(env, keyArray, &keyDatum);
+
+    if ( !valueDatum.dptr )
+	return 0;
+    if ( gdbm_errno != GDBM_NO_ERROR ) {
+	GDBM_EXCEPTION(env);
+	return 0;
+    }
+
+    valueArray = datumToArray(env, &valueDatum);
+    free(valueDatum.dptr);
+
+    return valueArray;
+}
+
+
+
+JNIEXPORT jboolean JNICALL 
+Java_au_com_pharos_gdbm_GdbmFile_gdbm_1exists
+  (JNIEnv *env, jobject obj, jlong dbf, jbyteArray keyArray)
+{
+    datum 	keyDatum;
+    int		result;
+
+    CHECK_NOT_NULL(dbf, env);
+    if (!arrayToDatum(env, keyArray, &keyDatum)) {
+	NULL_PTR_EXCEPTION(env);
+	return JNI_FALSE;
+    }
+    result = gdbm_exists(JLONG_TO_DBF(dbf), keyDatum);
+    if ( gdbm_errno != GDBM_NO_ERROR ) {
+	GDBM_EXCEPTION(env);
+	return 0;
+    }
+    releaseArrayAbort(env, keyArray, &keyDatum);
+    return result ? JNI_TRUE : JNI_FALSE;
+}
+
+
+
+
+
+JNIEXPORT void JNICALL 
+Java_au_com_pharos_gdbm_GdbmFile_gdbm_1store
+  (JNIEnv *env, jobject obj, jlong dbf, 
+   jbyteArray keyArray, jbyteArray valueArray, jboolean replace)
+{
+    datum	keyDatum;
+    datum	valueDatum;
+    
+    CHECK_NOT_NULL_VOID(dbf, env);
+    
+    if ( !arrayToDatum(env, keyArray, &keyDatum)
+	 || !arrayToDatum(env, valueArray, &valueDatum) ) {
+	NULL_PTR_EXCEPTION(env);
+	return;
+    }
+
+    gdbm_store(JLONG_TO_DBF(dbf), keyDatum, valueDatum, 
+	       replace ? GDBM_REPLACE : 0);
+
+    releaseArrayAbort(env, keyArray, &keyDatum);
+    releaseArrayAbort(env, valueArray, &valueDatum);
+
+    if ( gdbm_errno != GDBM_NO_ERROR )
+	GDBM_EXCEPTION(env);
+}
+
+
+
+JNIEXPORT void JNICALL 
+Java_au_com_pharos_gdbm_GdbmFile_gdbm_1delete
+   (JNIEnv *env, jobject obj, jlong dbf, jbyteArray keyArray)
+{
+    datum 	keyDatum;
+
+    CHECK_NOT_NULL_VOID(dbf, env);
+
+    if (!arrayToDatum(env, keyArray, &keyDatum)) {
+	NULL_PTR_EXCEPTION(env);
+	return;
+    }
+
+    gdbm_delete(JLONG_TO_DBF(dbf), keyDatum);
+
+    releaseArrayAbort(env, keyArray, &keyDatum);
+    
+    if ( gdbm_errno != GDBM_NO_ERROR )
+	GDBM_EXCEPTION(env);
+}
+
+
+
+JNIEXPORT jstring JNICALL 
+Java_au_com_pharos_gdbm_GdbmFile_gdbm_1getversion
+  (JNIEnv *env, jclass cls)
+{
+    return (*env)->NewStringUTF(env, gdbm_version);
+}
+
+
+JNIEXPORT jstring JNICALL 
+Java_au_com_pharos_gdbm_GdbmFile_gdbm_1wrapperVersion
+  (JNIEnv *env, jclass cls)
+{
+    return (*env)->NewStringUTF(env, "JavaGDBM release 0005 built " __DATE__);
+}
+				
+
+
+
+JNIEXPORT void JNICALL 
+Java_au_com_pharos_gdbm_GdbmFile_gdbm_1reorganize
+  (JNIEnv *env, jobject obj, jlong dbf)
+{
+    CHECK_NOT_NULL_VOID(dbf, env);
+
+    gdbm_reorganize(JLONG_TO_DBF(dbf));
+
+    if ( gdbm_errno != GDBM_NO_ERROR )
+	GDBM_EXCEPTION(env);
+}
+
+
+
+JNIEXPORT void JNICALL 
+Java_au_com_pharos_gdbm_GdbmFile_gdbm_1close
+  (JNIEnv *env, jobject obj, jlong dbf)
+{
+    CHECK_NOT_NULL_VOID(dbf, env);
+
+    gdbm_close(JLONG_TO_DBF(dbf));
+
+    if ( gdbm_errno != GDBM_NO_ERROR )
+	GDBM_EXCEPTION(env);
+}
+
+
+
+JNIEXPORT void JNICALL 
+Java_au_com_pharos_gdbm_GdbmFile_gdbm_1sync
+  (JNIEnv *env, jobject obj, jlong dbf)
+{
+    CHECK_NOT_NULL_VOID(dbf, env);
+
+    gdbm_sync(JLONG_TO_DBF(dbf));
+
+    if ( gdbm_errno != GDBM_NO_ERROR )
+	GDBM_EXCEPTION(env);
+}
+
+
+
+
+/**********************************************************************
+ *
+ * Following are support functions which aid in interfacing C to 
+ * Java. */
+
+/** Create a new Java byte array from a GDBM datum, and return a
+ * pointer thereto.  */
+
+jbyteArray datumToArray(JNIEnv *env, datum *fromDatum) 
+{
+    jbyteArray toArray;
+
+    if (!fromDatum || !fromDatum->dptr)
+	return 0;
+
+    toArray = (*env)->NewByteArray(env, fromDatum->dsize);
+    ASSERT(toArray);
+    (*env)->SetByteArrayRegion(env, toArray, 
+			       0, fromDatum->dsize, fromDatum->dptr);
+    
+    return toArray;
+}
+
+/** Convert a Java byte array to a GDBM datum.
+ *
+ * The Java array is pinned or copied for use in the datum, and must
+ * be released after use by releaseBytes. 
+ *
+ * Returns true if the array is non-null and could be pinned.  Otherwise,
+ * returns false. 
+ */
+int arrayToDatum(JNIEnv *env, jbyteArray fromArray, datum *toDatum)
+{
+    if (fromArray) {
+	toDatum->dptr = (*env)->GetByteArrayElements(env, fromArray, 0);
+	toDatum->dsize = (*env)->GetArrayLength(env, fromArray);
+	return (int) toDatum->dptr;
+    }
+    else 
+	return 0;
+}
+
+/** Release a byte array pinned or copied for use in a datum. */
+void releaseArray(JNIEnv *env, jbyteArray array, datum *fromDatum) 
+{
+    ASSERT(fromDatum->dptr);
+    (*env)->ReleaseByteArrayElements(env, array, fromDatum->dptr, 0);
+    fromDatum->dptr = 0;	/* no longer valid */
+}
+
+/** Release a byte array pinned or copied for use in a datum, aborting 
+ * any changes.  This potentially saves the runtime from having to 
+ * copy back an unchanged array. */
+void releaseArrayAbort(JNIEnv *env, jbyteArray array, datum *fromDatum) 
+{
+    ASSERT(fromDatum->dptr);
+    (*env)->ReleaseByteArrayElements(env, array, fromDatum->dptr, 
+				     JNI_ABORT);
+    fromDatum->dptr = 0;	/* no longer valid */
+}
+
+
+/** Throw a null pointer exception. */
+void nullPtrException(JNIEnv *env, const char *file, int line) 
+{
+    jclass exClass;
+    char reason[1024];
+    sprintf(reason, "Null pointer exception in GDBM wrapper (%s:%d)",
+	    file, line);
+    
+    exClass = (*env)->FindClass(env, "java/lang/NullPointerException");
+    ASSERT(exClass);
+
+    (*env)->ThrowNew(env, exClass, reason);
+}
+
+/** Translate the GDBM error into throw a Java exception, and throw
+ * same. 
+ *
+ * TODO: Throw different classes of exceptions depending on what the 
+ * underlying error is. 
+ */
+void gdbmException(JNIEnv *env, const char *file, int line) {
+    jclass exClass;
+    static char reason[1500];
+    static char srcLocation[500];
+
+    exClass = (*env)->FindClass(env, "au/com/pharos/gdbm/GdbmException");
+    ASSERT(exClass);
+
+    strncpy(reason, gdbm_strerror(gdbm_errno), 500);
+    sprintf(srcLocation, " (%s:%d)", file, line);
+
+    /* If the error code suggests that an OS or stdio error may have occurred,
+     * include supplementary information from errno. */
+    switch (gdbm_errno) {
+    case GDBM_FILE_OPEN_ERROR:
+    case GDBM_FILE_WRITE_ERROR:
+    case GDBM_FILE_SEEK_ERROR:
+    case GDBM_FILE_READ_ERROR:
+    case GDBM_MALLOC_ERROR:
+    case GDBM_REORGANIZE_FAILED:
+	strcat(reason, ": ");
+	strncat(reason, strerror(errno), 490);
+	strcat(reason, "?");
+    default:
+	/* errno is probably not useful */
+	;
+    }
+    
+    strncat(reason, srcLocation, 495);
+    gdbm_errno = GDBM_NO_ERROR;	/* this one has been handled */
+    (*env)->ThrowNew(env, exClass, reason);    
+}
+
+/* 
+ * Local variables:
+ * c-basic-offset: 4
+ * End:
+ */
Index: /greenstone3/trunk/src/packages/javagdbm/jni/win32.mak
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/jni/win32.mak	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/jni/win32.mak	(revision 14125)
@@ -0,0 +1,72 @@
+###########################################################################
+#
+# win32 makefile -- javagdbm\jni
+# 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.
+#
+###########################################################################
+
+JAVAGDBMHOME = ..
+ 
+GSDLHOME= $(GSDL3HOME)\gs2build
+GDBMHOME = $(GSDLHOME)\packages\windows\gdbm\gdbm
+
+AR = lib
+CC = cl
+CPPFLAGS = 
+
+DEFS = -D__WIN32__ -DHAVE_STRING_H
+
+INCLUDES = -I"$(GDBMHOME)" -I. \
+           -I"$(JAVA_HOME)\include" -I"$(JAVA_HOME)\include\win32"           
+
+COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) $(INCLUDES)
+
+.SUFFIXES:
+.SUFFIXES: .c .obj
+.c.obj:
+	$(COMPILE) $<
+
+ANSI2KNR = 
+o = .obj
+ 
+HEADERS = \
+    GdbmFile.h
+
+SOURCES = \
+    gdbmjava.c
+
+OBJECTS = \
+    gdbmjava$o   "$(GDBMHOME)\gdbm.lib"
+ 
+all : compile link
+
+compile:
+        $(COMPILE) gdbmjava.c
+
+link:
+        $(CC) -MD -LD $(OBJECTS) -Fegdbmjava.dll
+
+install: 
+        copy gdbmjava.dll "$(GSDL3HOME)\lib\jni"
+
+clean:
+	del *$o 
Index: /greenstone3/trunk/src/packages/javagdbm/winMake.bat
===================================================================
--- /greenstone3/trunk/src/packages/javagdbm/winMake.bat	(revision 14125)
+++ /greenstone3/trunk/src/packages/javagdbm/winMake.bat	(revision 14125)
@@ -0,0 +1,29 @@
+@echo off
+
+set MAKE=nmake
+set MAKE_OPTIONS=/f
+
+if ""%1"" == """" goto all
+if ""%1"" == ""compile"" goto go
+if ""%1"" == ""install"" goto go
+if ""%1"" == ""clean"" goto go
+
+:unknown
+	echo Error: Unrecognized argument %1.
+	goto done
+
+:go
+	if ""%2"" == ""javaonly"" goto java
+
+:all
+	cd jni
+	%MAKE% %MAKE_OPTIONS% win32.mak %1
+	cd ..
+
+:java
+	cd java
+	call winMake.bat %1
+	cd ..
+	goto done
+
+:done
Index: /greenstone3/trunk/web/WEB-INF/classes/AbstractBrowse.properties
===================================================================
--- /greenstone3/trunk/web/WEB-INF/classes/AbstractBrowse.properties	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/classes/AbstractBrowse.properties	(revision 14125)
@@ -0,0 +1,3 @@
+ClassifierBrowse.name=Browse
+ClassifierBrowse.description=Browse pre-defined classification hierarchies
+ClassifierBrowse.classifier_help:Browse by {0}
Index: /greenstone3/trunk/web/WEB-INF/classes/AbstractGS2FieldSearch.properties
===================================================================
--- /greenstone3/trunk/web/WEB-INF/classes/AbstractGS2FieldSearch.properties	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/classes/AbstractGS2FieldSearch.properties	(revision 14125)
@@ -0,0 +1,33 @@
+#query params
+param.level=Granularity to search at
+param.sortBy=Document display order
+param.sortBy.1=ranked
+param.sortBy.0=natural
+param.fqv=Word or phrase 
+param.fqf=in field
+param.fqf.all=All fields
+param.fqs=stem
+param.fqc=case
+param.fqk=
+param.fqk.0=AND
+param.fqk.1=OR
+param.fqk.2=NOT
+param.fqa=accent
+param.indexSubcollection=Index sub collection
+param.indexLanguage=Index language
+
+#levels - this should go somewhere more central perhaps?
+level.document=Document
+level.Doc=Document
+level.section=Section
+level.Sec=Section
+level.paragraph=Paragraph
+level.Para=Paragraph
+
+#service stuff
+FieldQuery.name=Form Search
+FieldQuery.description=Simple fielded search
+FieldQuery.submit=Search
+AdvancedFieldQuery.name=Advanced Search
+AdvancedFieldQuery.description=Advanced fielded searching
+AdvancedFieldQuery.submit=Search
Index: /greenstone3/trunk/web/WEB-INF/classes/AbstractSearch.properties
===================================================================
--- /greenstone3/trunk/web/WEB-INF/classes/AbstractSearch.properties	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/classes/AbstractSearch.properties	(revision 14125)
@@ -0,0 +1,21 @@
+#service stuff
+TextQuery.name=Text Search
+TextQuery.description=Full text and/or metadata search service
+TextQuery.submit=Search
+
+#compulsory query params
+param.index=Index to search in
+param.maxDocs=Maximum hits to return
+param.query=Query string
+param.hitsPerPage=Hits per page
+param.startPage=Start from page
+
+#optional params
+param.stem=Turn stemming 
+param.case=Turn casefolding 
+param.accent=Turn accentfolding 
+param.matchMode=Match
+param.matchMode.all=all
+param.matchMode.some=some
+param.boolean.on=on
+param.boolean.off=off
Index: /greenstone3/trunk/web/WEB-INF/classes/CrossCollectionSearch.properties
===================================================================
--- /greenstone3/trunk/web/WEB-INF/classes/CrossCollectionSearch.properties	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/classes/CrossCollectionSearch.properties	(revision 14125)
@@ -0,0 +1,6 @@
+TextQuery.name=Cross collection search
+TextQuery.submit=Search
+TextQuery.description=Search over multiple collections
+param.query=Query string
+param.collection=Collections to search in
+param.collection.all=All collections
Index: /greenstone3/trunk/web/WEB-INF/classes/GATEServices.properties
===================================================================
--- /greenstone3/trunk/web/WEB-INF/classes/GATEServices.properties	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/classes/GATEServices.properties	(revision 14125)
@@ -0,0 +1,11 @@
+# Service parameters
+param.annotationType=Annotation type
+param.annotationType.Address=Address
+param.annotationType.Date=Date
+param.annotationType.Location=Places
+param.annotationType.Organization=Organization
+param.annotationType.Person=People
+
+#service stuff
+GatePOSTag.name=Annotate document
+GatePOSTag.submit=Go
Index: /greenstone3/trunk/web/WEB-INF/classes/GS2Construct.properties
===================================================================
--- /greenstone3/trunk/web/WEB-INF/classes/GS2Construct.properties	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/classes/GS2Construct.properties	(revision 14125)
@@ -0,0 +1,67 @@
+#the params used by the services
+param.collection=Collection
+param.creator=Creator's email address
+param.collTitle=Collection title
+param.collAbout=Collection description
+param.buildType=Building type
+param.buildType.mg=MG
+param.buildType.mgpp=MGPP
+
+#service names and submit buttons
+DeleteCollection.name=Delete
+DeleteCollection.description=Delete a collection 
+DeleteCollection.submit=Delete
+NewCollection.name=Create
+NewCollection.description=Create a new collection
+NewCollection.submit=Create
+ImportCollection.name=Import
+ImportCollection.description=Import a collection: take the original documents and convert them to Greenstone internal format
+ImportCollection.submit=Import
+BuildCollection.name=Build
+BuildCollection.description=Build a collection: create the indexes and browsable hierarchies.
+BuildCollection.submit=Build
+ActivateCollection.name=Activate
+ActivateCollection.description=Activate a collection: Replace the old built collection with the new version
+ActivateCollection.submit=Activate
+ReloadCollection.name=Reload
+ReloadCollection.description=Reload a collection into the library
+ReloadCollection.submit=Reload
+
+#error messages used by each service - {0} is the collection name
+#DeleteCollection######
+delete.configure_error=Couldn't deactivate {0} from the library.
+delete.delete_error=Couldn't delete {0}.
+delete.success=Collection {0} deleted successfully.
+delete.exists_error=Collection {0} did not exist and couldn't be deleted.
+
+#NewCollection######
+new.success=Collection {0} created successfully.
+
+#ImportCollection#####
+import.success=Collection {0} imported successfully.
+
+#BuildCollection#####
+build.success=Collection {0} built successfully.
+
+#ActivateCollection#####
+activate.build_dir_error=Collection {0} had no building directory: couldn't be activated.
+activate.build_config_error=Collection {0} had no building config file: couldn't be activated.
+activate.rm_index_error=Couldn't remove the index directory.
+activate.rename_building_error=Couldn't rename building to index.
+activate.success=Collection {0} activated successfully.
+
+#ReloadCollection#####
+reload.success=Collection {0} reloaded successfully.
+reload.activate_error=Couldn't activate collection {0} in the library.
+
+#general stuff
+general.process_id_error=Invalid process id.
+general.configure_constructor_error=Couldn't configure the collection constructor.
+general.process_start=Starting process...
+
+
+
+
+
+
+
Index: /greenstone3/trunk/web/WEB-INF/classes/GS2Construct_fr.properties
===================================================================
--- /greenstone3/trunk/web/WEB-INF/classes/GS2Construct_fr.properties	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/classes/GS2Construct_fr.properties	(revision 14125)
@@ -0,0 +1,51 @@
+#the params used by the services
+param.collection=Collection <fr>
+param.creator=Creator's email address <fr>
+param.collectionName=Name of the collection <fr>
+
+#service names and submit buttons
+DeleteCollection.name=Delete a collection <fr>
+DeleteCollection.submit=Delete <fr>
+
+#messages for each service
+#DeleteCollection######
+delete.deactivate_error=Couldn't deactivate {0} from the library. <fr>
+delete.delete_error=Couldn't delete {0}. <fr>
+delete.success=Collection {0} deleted successfully. <fr>
+delete.submit=Delete <fr>
+
+#NewCollection######
+new.success=Collection {0} created successfully. <fr>
+new.submit=Create <fr>
+
+#ImportCollection#####
+import.success=Collection {0} imported successfully. <fr>
+import.submit=Import <fr>
+
+#BuildCollection#####
+build.success=Collection {0} built successfully. <fr>
+build.submit=Build <fr>
+
+#ActivateCollection#####
+#activate.build_dir_error=Collection {0} had no building directory: couldn't be activated. <fr>
+activate.build_config_error=Collection {0} had no building config file: couldn't be activated. <fr>
+activate.rm_index_error=Couldn't remove the index directory. <fr>
+activate.rename_building_error=Couldn't rename building to index. <fr>
+activate.success=Collection {0} activated successfully. <fr>
+activate.submit=Activate <fr>
+
+#ReloadCollection#####
+reload.success=Collection {0} reloaded successfully. <fr>
+reload.activate_error=Couldn't activate collection {0} in the library. <fr>
+reload.submit=Reload <fr>
+
+
+
+
+
+
+
+
+
+
+
Index: /greenstone3/trunk/web/WEB-INF/classes/GS2LuceneSearch.properties
===================================================================
--- /greenstone3/trunk/web/WEB-INF/classes/GS2LuceneSearch.properties	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/classes/GS2LuceneSearch.properties	(revision 14125)
@@ -0,0 +1,2 @@
+param.sortBy=Sort search results by
+param.sortBy.rank=rank
Index: /greenstone3/trunk/web/WEB-INF/classes/IViaSearch.properties
===================================================================
--- /greenstone3/trunk/web/WEB-INF/classes/IViaSearch.properties	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/classes/IViaSearch.properties	(revision 14125)
@@ -0,0 +1,7 @@
+#query params
+param.index.au=Author
+param.index.ti=Title
+param.index.kw=Keywords
+param.index.su=Subject
+param.index.de=Description
+param.index.fu=Full Text
Index: /greenstone3/trunk/web/WEB-INF/classes/LuceneSearch.properties
===================================================================
--- /greenstone3/trunk/web/WEB-INF/classes/LuceneSearch.properties	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/classes/LuceneSearch.properties	(revision 14125)
@@ -0,0 +1,5 @@
+TextQuery.name=Search
+TextQuery.submit=Search
+TextQuery.description=A simple XML search service
+
+param.query=Enter your query string
Index: /greenstone3/trunk/web/WEB-INF/classes/MapRetrieve.properties
===================================================================
--- /greenstone3/trunk/web/WEB-INF/classes/MapRetrieve.properties	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/classes/MapRetrieve.properties	(revision 14125)
@@ -0,0 +1,3 @@
+#service stuff
+MapRetrieve.name=Maps Retrieved
+DocumentMetadataRetrieve.name=Retrieved Documents
Index: /greenstone3/trunk/web/WEB-INF/classes/MapSearch.properties
===================================================================
--- /greenstone3/trunk/web/WEB-INF/classes/MapSearch.properties	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/classes/MapSearch.properties	(revision 14125)
@@ -0,0 +1,4 @@
+#service stuff
+TextQuery.name=Map Search
+TextQuery.description=Search for placenames in maps
+TextQuery.submit=Search
Index: /greenstone3/trunk/web/WEB-INF/classes/PhindPhraseBrowse.properties
===================================================================
--- /greenstone3/trunk/web/WEB-INF/classes/PhindPhraseBrowse.properties	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/classes/PhindPhraseBrowse.properties	(revision 14125)
@@ -0,0 +1,2 @@
+PhindApplet.name=Phrase browse
+PhindApplet.description=Java applet that allows you to browse extracted phrase hierarchies
Index: /greenstone3/trunk/web/WEB-INF/classes/TestServlet.java
===================================================================
--- /greenstone3/trunk/web/WEB-INF/classes/TestServlet.java	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/classes/TestServlet.java	(revision 14125)
@@ -0,0 +1,15 @@
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/** a test servlet to make sure the servlet container is working */
+public class TestServlet extends HttpServlet {
+
+    public void doGet(HttpServletRequest request,
+		      HttpServletResponse response)
+	throws ServletException, IOException {
+
+	PrintWriter out = response.getWriter();
+	out.println("Hello Greenstone!");
+    }
+}
Index: /greenstone3/trunk/web/WEB-INF/classes/Visualizer.properties
===================================================================
--- /greenstone3/trunk/web/WEB-INF/classes/Visualizer.properties	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/classes/Visualizer.properties	(revision 14125)
@@ -0,0 +1,2 @@
+VisApplet.name=Query Visualizer
+VisApplet.description=Visualize your query...
Index: /greenstone3/trunk/web/WEB-INF/classes/config_format.xsl
===================================================================
--- /greenstone3/trunk/web/WEB-INF/classes/config_format.xsl	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/classes/config_format.xsl	(revision 14125)
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:xslt="output.xsl"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:gsf="http://www.greenstone.org/configformat"
+  extension-element-prefixes="java">
+  
+  <xsl:output method="xml"/>
+  <xsl:namespace-alias
+    stylesheet-prefix="xslt" result-prefix="xsl"/>
+
+
+  <xsl:template match="format">
+    <format hello="yes">
+      <xsl:apply-templates/>
+    </format>
+  </xsl:template>
+  
+  <xsl:template match="gsf:template">
+    <xslt:template>
+      <xsl:copy-of select="@*"/>
+      <xsl:attribute name="priority">2</xsl:attribute> 
+      <xsl:if test=".//gsf:link/@type">
+	<xslt:param name="serviceName">service-name</xslt:param>
+      </xsl:if>
+      <xsl:if test=".//gsf:link">
+	<xslt:param name="collName">coll-name</xslt:param>
+	<xslt:variable name='library' select='ancestor::page/config/library_name'/>
+      </xsl:if>
+      <xsl:apply-templates/>
+    </xslt:template>
+  </xsl:template>
+  
+  <xsl:template match="gsf:link">
+    <xsl:choose>
+      <xsl:when test="@type='classifier'">
+	<a><xslt:attribute name='href'><xslt:value-of select='$library'/>?a=b&amp;s=<xslt:value-of select='$serviceName'/>&amp;c=<xslt:value-of select='$collName'/>&amp;cl=<xslt:value-of select='@nodeID'/><xslt:if test="classifierNode|documentNode">.pr</xslt:if></xslt:attribute>
+	  <xsl:apply-templates/>
+	</a>
+      </xsl:when>
+      <xsl:otherwise> <!-- a document link -->
+	<a><xsl:attribute name="href">{$library}?a=d&amp;c={$collName}&amp;d={@nodeID}</xsl:attribute>
+	  <xsl:apply-templates/>
+	</a>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="gsf:icon">
+    <xsl:choose>
+      <xsl:when test="@type='classifier'">
+	<img src='interfaces/default/images/bshelf.gif' border='0' width='20' height='16' />
+      </xsl:when>
+      <xsl:otherwise>
+	<xslt:apply-templates select="." mode="displayNodeIcon"/>
+	<!--
+	<img src='interfaces/default/images/book.gif' width='18' height='11' border='0'/>-->
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="gsf:metadata">    
+    <xslt:value-of><xsl:attribute name="select">metadataList/metadata[@name='<xsl:value-of select="@name"/>']</xsl:attribute></xslt:value-of>
+  </xsl:template>
+
+<!--
+  <xsl:template match="gsf:text">
+TODO
+  </xsl:template>
+-->
+  <xsl:template match="*">
+    <xsl:copy>
+      <xsl:copy-of select="@*"/>
+      <xsl:apply-templates/>
+    </xsl:copy>
+  </xsl:template>
+
+
+<!-- copied from style for now-->
+<!-- Display the appropriate image, depending on the node type -->
+<xsl:template match="documentNode" mode="displayNodeIcon">
+
+  <!-- Root node: book icon (open or closed) -->
+  <xsl:if test="@nodeType='root'">
+    <xsl:choose>
+      <xsl:when test="documentNode">
+	<img border="0" width="28" height="23"
+	     src="interfaces/default/images/openbook.gif"
+	     alt="Close this book"/>
+      </xsl:when>
+      <xsl:otherwise>
+	<img border="0" width="18" height="11"
+	     src="interfaces/default/images/book.gif"
+	     alt="Open this document and view contents"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:if>
+
+  <!-- Interior node: folder icon (open or closed) -->
+  <xsl:if test="@nodeType='interior'">
+    <xsl:choose>
+      <xsl:when test="documentNode">
+	<img border="0" width="23" height="15"
+	     src="interfaces/default/images/openfldr.gif"
+	     alt="Close this folder"/>
+      </xsl:when>
+      <xsl:otherwise>
+	<img border="0" width="23" height="15"
+	     src="interfaces/default/images/clsdfldr.gif"
+	     alt="Open this folder and view contents"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:if>
+
+  <!-- Leaf node: page icon -->
+  <xsl:if test="@nodeType='leaf'">
+    <img border="0" width="16" height="21"
+	 src="interfaces/default/images/itext.gif"
+	 alt="View the document"/>
+  </xsl:if>
+</xsl:template>
+
+</xsl:stylesheet>
+
+
Index: /greenstone3/trunk/web/WEB-INF/classes/interface_classic.properties
===================================================================
--- /greenstone3/trunk/web/WEB-INF/classes/interface_classic.properties	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/classes/interface_classic.properties	(revision 14125)
@@ -0,0 +1,110 @@
+nzdl=New Zealand Digital Library
+home_b=HOME
+pref_b=PREFERENCES
+help_b=HELP
+# text for the titles (in the page header)
+help_t=help
+pref_t=preferences
+about_t=about
+search_t=search
+phrases_t=phrases
+texticonpdf=View the PDF document
+texticonps=View the PostScript document
+texticonrtf=View the RTF document
+texticonmsword=View the Microsoft Word document
+texticonppt=View the PowerPoint document
+texticonxls=View the Microsoft Excel document
+#################
+# home page
+#################
+home.feedback=Feedback
+home.aboutgs=About<br/>Greenstone
+home.people=People
+home.research=Research
+home.projects=Projects
+home.software=Software
+home.publications=Publications
+home.coll_warning=This interface is designed to look and behave like the classic Greenstone 2 style interface. It makes assumptions about the services that a collection might have: it looks for the TextQuery/FormQuery/AdvancedFormQuery and ClassifierBrowse services. If a query service is present, a search button is added to the navigation bar. If more than one query service is available they come under the same button, and are selectable via the preferences page. If ClassifierBrowse is present, the classifiers provided by that service are displayed on the navigation bar instead of the service itself. Any other services are ignored. Greenstone 2 collections work exactly as they would in a Greenstone 2 library, while some other collections do not work properly.
+##################
+# about page
+##################
+aboutpage=About page
+#about.services=Services available:
+#about.description=Description:
+about.aboutcoll=About this collection
+about.howtofind=How to find information in the {0} collection
+##################
+# prefs page
+##################
+pref.searchpref=Search preferences
+pref.prespref=Presentation preferences
+pref.interfacelang=Interface language:
+pref.encoding=Encoding:
+##################
+# query page
+##################
+query.wordcount=Word count:
+query.nodocsmatch=No documents matched the query.
+query.onedocsmatch=One document matched the query.
+query.manydocsmatch={0} documents matched the query.
+query.matches=Matches
+query.results=results
+##################
+# help page
+##################
+help.numbrowseoptions=There are {0} ways to find information in this collection:
+help.simplehelpheading=How to find information in the {0} collection
+help.Searchshort=search for particular words
+help.Searchlong=<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.
+help.Titleshort=access publications by title
+help.Titlelong=<p />You can <i>access publications by title</i> by pressing the <i>titles</i> button.  This brings up a list of books in alphabetic order.
+help.Organizationshort=access publications by organisation
+help.Organizationlong=<p />You can <i>access publications by organisation</i> by pressing the <i>organisations</i> button.  This brings up a list of organisations.
+help.Organisationshort=access publications by organisation
+help.Organisationlong=<p />You can <i>access publications by organisation</i> by pressing the <i>organisations</i> button.  This brings up a list of organisations.
+help.HowToshort=access publications by "how to" listing
+help.HowTolong=<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.
+help.Howtoshort=access publications by "how to" listing
+help.Howtolong=<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.
+help.Creatorshort=access publications by author
+help.Creatorlong=<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.  
+help.Subjectshort=access publications by subject
+help.Subjectlong=<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.
+help.Topicshort=access publications by topic
+help.Topiclong=<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.  
+help.Toshort=access publications by To field
+help.Tolong=<p>You can <i>access publications by To field</i> by pressing the <i>to</i> button.  This brings up a list of addressees.  
+help.Fromshort=access publications by From field
+help.Fromlong=<p>You can <i>access publications by From field</i> by pressing the <i>from</i> button.  This brings up a list of senders.  
+help.Seriesshort=access publications by series
+help.Serieslong=<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.  
+help.Dateshort=access publications by date
+help.Datelong=<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.  
+help.Browseshort=browse publications
+help.Browselong=<p>You can <i>browse publications</i> by pressing the <i>browse</i> button.  
+help.Peopleshort=access publications by people
+help.Peoplelong=<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.  
+help.Languageshort=access publications by language
+help.Languagelong=<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.  
+help.Acronymshort=access publications by acronym
+help.Acronymlong=<p>You can <i>access publications by acronym occurrence</i> bypressing the <i>acronyms</i> button.  This brings up a list of the acronyms, and the places that they occur.  
+help.Phraseshort=browse phrases occurring in publications
+help.Phraselong=<p>You can <i>browse phrases occurring in publications</i> by pressing the <i>phrases</i> button.  This uses the phind phrase browser.  
+help.Artistshort=access publications by artist
+help.Artistlong=<p>You can <i>access publications by artist</i> by pressing the <i>artists</i> button.  This brings up a list of entries, sorted by artist name.  
+help.Sourceshort=access publications by filename
+help.Sourcelong=<p>You can <i>access publications by filename</i> by pressing the <i>filenames</i> button.  This brings up a list of entries, sorted by original filename.  
+help.Keywordshort=access publications by keyword
+help.Keywordlong=<p>You can <i>access publications by keyword</i> by pressing the <i>keywords</i> button.  This brings up a list of keywords. 
+help.Volumeshort=access publications by volume
+help.Volumelong=<p>You can <i>access publications by volume</i> by pressing the <i>volumes</i> button. This brings up a list of volumes. 
+help.Captionsshort=access publications by caption
+help.Captionslong=<p>You can <i>access publications by caption</i> by pressing the <i>captions</i> button. This brings up a list of captions. 
+help.Countriesshort=access publications by country
+help.Countrieslong=<p>You can <i>access publications by country</i> by pressing the <i>countries</i> button. This brings up a list of countries. 
+help.short=undefined classification
+help.defaultshort=undefined classification
+help.long=<p>Click on the <i>unknown</i> button to browse publications (listing is sorted by an unknown field).  
+help.defaultlong=<p>Click on the <i>unknown</i> button to browse publications (listing is sorted by an unknown field).  
+
+
Index: /greenstone3/trunk/web/WEB-INF/classes/interface_default.properties
===================================================================
--- /greenstone3/trunk/web/WEB-INF/classes/interface_default.properties	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/classes/interface_default.properties	(revision 14125)
@@ -0,0 +1,72 @@
+gsdl=Greenstone Digital Library Software
+gs3power=powered by greenstone3
+# the buttons
+home_b=HOME
+help_b=HELP
+pref_b=PREFERENCES
+# tool tips for the buttons
+home_tip=Library home page
+help_tip=Help pages
+pref_tip=Change your interface preferences
+# page titles
+help_t=help
+pref_t=preferences
+aboutpage=About page
+textframebrowser=You must have a frame enabled browser to view this.
+#######################
+# query page
+########################
+about.noservices=There are no services available for this collection.
+about.services=Services available:
+about.servicehelp=You can access the services by clicking on the buttons below or on the names on the navigation bar. The navigation bar is persistent across all pages in the collection.
+#about.description=Description:
+about.metadata=Metadata:
+
+#######################
+# query page
+########################
+query.wordcount=Word count:
+query.nodocsmatch=No documents matched the query.
+query.onedocsmatch=One document matched the query.
+query.manydocsmatch={0} documents matched the query.
+query.atleastdocsmatch=At least {0} documents matched the query.
+query.docsreturned={0} documents returned.
+query.matches=Matches
+query.results=Results
+###############
+# document page
+##################
+document.pageof=Page {0} of {1}.
+document.pages={0} pages.
+document.gotopage=Go to page
+
+##################
+# prefs page
+##################
+pref.searchpref=Search preferences
+pref.prespref=Presentation preferences
+pref.interfacelang=Interface language:
+pref.encoding=Encoding:
+pref.hitsperpage=Number of hits per page:
+pref.all=all
+pref.set_prefs=Set preferences
+pref.berrybasket=Berry basket
+pref.berrybasket.on=on
+pref.berrybasket.off=off
+pref.book=Book viewer mode: 
+
+
+##################
+# docs page
+##################
+doc.expand_doc_b=EXPAND<br />DOCUMENT
+doc.expand_doc_tip=Display the entire document
+doc.contract_doc_b=CONTRACT<br />DOCUMENT
+doc.contract_doc_tip=Return to previously selected section
+doc.expand_contents_b=EXPAND<br />CONTENTS 
+doc.expand_contents_tip=Expand only the table of contents
+doc.contract_contents_b=CONTRACT<br />CONTENTS
+doc.contract_contents_tip=Collapse the table of contents
+doc.detach_page_b=DETACH<br />PAGE
+doc.detach_page_tip=Open this page in a new window
+
Index: /greenstone3/trunk/web/WEB-INF/classes/interface_default_fr.properties
===================================================================
--- /greenstone3/trunk/web/WEB-INF/classes/interface_default_fr.properties	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/classes/interface_default_fr.properties	(revision 14125)
@@ -0,0 +1,6 @@
+nzdl=Bibliothèque Numérique Greenstone
+home=ACCUEIL
+aboutpage=About page (fr)
+about.services=Services available (fr):
+about.description=Description (fr):
+query.matches=Résultats
Index: /greenstone3/trunk/web/WEB-INF/classes/interface_nzdl.properties
===================================================================
--- /greenstone3/trunk/web/WEB-INF/classes/interface_nzdl.properties	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/classes/interface_nzdl.properties	(revision 14125)
@@ -0,0 +1,108 @@
+nzdl=New Zealand Digital Library
+home_b=HOME
+pref_b=PREFERENCES
+help_b=HELP
+# text for the titles (in the page header)
+home_t=home
+help_t=help
+pref_t=preferences
+about_t=about
+search_t=search
+phrases_t=phrases
+#################
+# home page
+#################
+home.feedback=Feedback
+home.aboutgs=About<br/>Greenstone
+home.people=People
+home.research=Research
+home.projects=Projects
+home.software=Software
+home.publications=Publications
+##################
+# about page
+##################
+aboutpage=About page
+#about.services=Services available:
+#about.description=Description:
+about.aboutcoll=About this collection
+about.howtofind=How to find information in the {0} collection
+##################
+# prefs page
+##################
+pref.searchpref=Search preferences
+pref.prespref=Presentation preferences
+pref.interfacelang=Interface language:
+pref.encoding=Encoding:
+##################
+# query page
+##################
+query.wordcount=Word count:
+query.nodocsmatch=No documents matched the query.
+query.onedocsmatch=One document matched the query.
+query.manydocsmatch={0} documents matched the query.
+query.matches=Matches
+query.results=results
+##################
+# help page
+##################
+help.numbrowseoptions=There are {0} ways to find information in this collection:
+help.simplehelpheading=How to find information in the {0} collection
+help.Searchshort=search for particular words
+help.Searchlong=<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.
+help.Titleshort=access publications by title
+help.Titlelong=<p />You can <i>access publications by title</i> by pressing the <i>titles</i> button.  This brings up a list of books in alphabetic order.
+help.Organizationshort=access publications by organisation
+help.Organizationlong=<p />You can <i>access publications by organisation</i> by pressing the <i>organisations</i> button.  This brings up a list of organisations.
+help.Organisationshort=access publications by organisation
+help.Organisationlong=<p />You can <i>access publications by organisation</i> by pressing the <i>organisations</i> button.  This brings up a list of organisations.
+help.HowToshort=access publications by "how to" listing
+help.HowTolong=<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.
+help.Howtoshort=access publications by "how to" listing
+help.Howtolong=<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.
+help.Creatorshort=access publications by author
+help.Creatorlong=<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.  
+help.Subjectshort=access publications by subject
+help.Subjectlong=<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.
+help.Topicshort=access publications by topic
+help.Topiclong=<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.  
+help.Toshort=access publications by To field
+help.Tolong=<p>You can <i>access publications by To field</i> by pressing the <i>to</i> button.  This brings up a list of addressees.  
+help.Fromshort=access publications by From field
+help.Fromlong=<p>You can <i>access publications by From field</i> by pressing the <i>from</i> button.  This brings up a list of senders.  
+help.Seriesshort=access publications by series
+help.Serieslong=<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.  
+help.Dateshort=access publications by date
+help.Datelong=<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.  
+help.Browseshort=browse publications
+help.Browselong=<p>You can <i>browse publications</i> by pressing the <i>browse</i> button.  
+help.Peopleshort=access publications by people
+help.Peoplelong=<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.  
+help.Languageshort=access publications by language
+help.Languagelong=<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.  
+help.Acronymshort=access publications by acronym
+help.Acronymlong=<p>You can <i>access publications by acronym occurrence</i> bypressing the <i>acronyms</i> button.  This brings up a list of the acronyms, and the places that they occur.  
+help.Phraseshort=browse phrases occurring in publications
+help.Phraselong=<p>You can <i>browse phrases occurring in publications</i> by pressing the <i>phrases</i> button.  This uses the phind phrase browser.  
+help.Artistshort=access publications by artist
+help.Artistlong=<p>You can <i>access publications by artist</i> by pressing the <i>artists</i> button.  This brings up a list of entries, sorted by artist name.  
+help.Sourceshort=access publications by filename
+help.Sourcelong=<p>You can <i>access publications by filename</i> by pressing the <i>filenames</i> button.  This brings up a list of entries, sorted by original filename.  
+help.Keywordshort=access publications by keyword
+help.Keywordlong=<p>You can <i>access publications by keyword</i> by pressing the <i>keywords</i> button.  This brings up a list of keywords. 
+help.Volumeshort=access publications by volume
+help.Volumelong=<p>You can <i>access publications by volume</i> by pressing the <i>volumes</i> button. This brings up a list of volumes. 
+help.Captionsshort=access publications by caption
+help.Captionslong=<p>You can <i>access publications by caption</i> by pressing the <i>captions</i> button. This brings up a list of captions. 
+help.Countriesshort=access publications by country
+help.Countrieslong=<p>You can <i>access publications by country</i> by pressing the <i>countries</i> button. This brings up a list of countries. 
+help.short=undefined classification
+help.defaultshort=undefined classification
+help.long=<p>Click on the <i>unknown</i> button to browse publications (listing is sorted by an unknown field).  
+help.defaultlong=<p>Click on the <i>unknown</i> button to browse publications (listing is sorted by an unknown field).  
+#################################
+#stuff for individual collections
+#################################
+collect.SearchBySender=search by sender
+
+
Index: /greenstone3/trunk/web/WEB-INF/classes/metadata_names.properties
===================================================================
--- /greenstone3/trunk/web/WEB-INF/classes/metadata_names.properties	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/classes/metadata_names.properties	(revision 14125)
@@ -0,0 +1,36 @@
+Subject=Subject
+Subject.buttonname=subjects
+Title=Title
+Title.buttonname=titles
+Organisation=Organisation
+Organisation.buttonname=organisations
+Organization=Organisation
+Organization.buttonname=organisations
+Keyword=Keyword
+Keyword.buttonname=keywords
+HowTo=How To
+HowTo.buttonname=how to
+Howto=How To
+Howto.buttonname=how to
+Creator=Creator
+Creator.buttonname=creators
+Date=Date
+Date.buttonname=dates
+From=From
+From.buttonname=senders
+To=To
+To.buttonname=recipients
+Source=Source
+Source.buttonname=filenames
+Acronym=Acronym
+Acronym.buttonname=acronyms
+Topic=Topic
+Topic.buttonname=topics
+Collage=Collage
+Collage.buttonname=collage
+Countries=Countries
+Countries.buttonname=countries
+Language=Language
+Language.buttonname=languages
+Artist=Artist
+Artist.buttonname=artists
Index: /greenstone3/trunk/web/WEB-INF/web.xml
===================================================================
--- /greenstone3/trunk/web/WEB-INF/web.xml	(revision 14125)
+++ /greenstone3/trunk/web/WEB-INF/web.xml	(revision 14125)
@@ -0,0 +1,286 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<!DOCTYPE web-app 
+    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
+    "http://java.sun.com/dtd/web-app_2_3.dtd">
+
+<!-- this is based on a sample web.xml file provided by 
+http://jakarta.apache.org/tomcat/tomcat-4.0-doc/appdev/web.xml.txt
+-->
+<web-app>
+
+
+  <!-- General description of your web application -->
+  
+  <display-name>GSDL3</display-name>
+  <description>
+    Greenstone digital library version 3.
+  </description>
+  
+  
+  <!-- Context initialization parameters that define shared
+  String constants used within your application, which
+  can be customized by the system administrator who is
+  installing your application.  The values actually
+  assigned to these parameters can be retrieved in a
+  servlet or JSP page by calling:
+  
+  String value =
+  getServletContext().getInitParameter("name");
+  
+  where "name" matches the <param-name> element of
+  one of these initialization parameters.
+  
+  You can define any number of context initialization
+  parameters, including zero.
+  -->
+  
+  <context-param>
+    <param-name>webmaster</param-name>
+    <param-value>greenstone3@list.scms.waikato.ac.nz</param-value>
+    <description>
+      The EMAIL address of the administrator to whom questions
+      and comments about this application should be addressed.
+    </description>
+  </context-param>
+  
+
+  <!-- Servlet definitions for the servlets that make up
+  your web application, including initialization
+  parameters.  With Tomcat, you can also send requests
+  to servlets not listed here with a request like this:
+
+  http://localhost:8080/{context-path}/servlet/{classname}
+  
+  but this usage is not guaranteed to be portable.  It also
+  makes relative references to images and other resources
+  required by your servlet more complicated, so defining
+  all of your servlets (and defining a mapping to them with
+  a servlet-mapping element) is recommended.
+  
+  Servlet initialization parameters can be retrieved in a
+  servlet or JSP page by calling:
+  
+  String value =
+  getServletConfig().getInitParameter("name");
+  
+  where "name" matches the <param-name> element of
+  one of these initialization parameters.
+  
+  You can define any number of servlets, including zero.
+  -->
+
+  <servlet>
+    <servlet-name>tester</servlet-name>
+    <description>a test servlet</description>
+    <servlet-class>TestServlet</servlet-class>
+  </servlet>
+  
+  <servlet>
+    <servlet-name>library</servlet-name>
+    <description>standard gsdl3 library program: uses localsite and the default interface</description>
+    <servlet-class>org.greenstone.gsdl3.LibraryServlet</servlet-class>
+    <init-param>
+      <param-name>library_name</param-name>
+      <param-value>library</param-value>
+    </init-param>
+    <init-param>
+      <param-name>site_name</param-name>
+      <param-value>localsite</param-value>
+    </init-param>
+    <init-param>
+      <param-name>interface_name</param-name>
+      <param-value>default</param-value>
+    </init-param>
+    <init-param>
+      <param-name>default_lang</param-name>
+      <param-value>en</param-value>
+    </init-param>
+  </servlet>
+  
+  <servlet>
+    <servlet-name>gateway</servlet-name>
+    <description>gsdl3 library based on gateway site and default interface. It uses SOAP to talk to localsite</description>
+    <servlet-class>org.greenstone.gsdl3.LibraryServlet</servlet-class>
+    <init-param>
+      <param-name>library_name</param-name>
+      <param-value>gateway</param-value>
+    </init-param>
+    <init-param>
+      <param-name>site_name</param-name>
+      <param-value>gateway</param-value>
+    </init-param>
+    <init-param>
+      <param-name>interface_name</param-name>
+      <param-value>default</param-value>
+    </init-param>
+    <init-param>
+      <param-name>default_lang</param-name>
+      <param-value>en</param-value>
+    </init-param>
+  </servlet>
+  
+  <servlet>
+    <servlet-name>classic-library</servlet-name>
+    <description>Greenstone 2 lookalike library program: uses localsite with the classic interface</description>
+    <servlet-class>org.greenstone.gsdl3.LibraryServlet</servlet-class>
+    <init-param>
+      <param-name>library_name</param-name>
+      <param-value>classic</param-value>
+    </init-param>
+    <init-param>
+      <param-name>site_name</param-name>
+      <param-value>localsite</param-value>
+    </init-param>
+    <init-param>
+      <param-name>interface_name</param-name>
+      <param-value>classic</param-value>
+    </init-param>
+    <init-param>
+      <param-name>default_lang</param-name>
+      <param-value>en</param-value>
+    </init-param>
+    <init-param>
+      <param-name>params_class</param-name>
+      <param-value>NZDLParams</param-value>
+    </init-param>
+  </servlet>
+
+  <!-- axis servlets -->
+  <servlet>
+    <servlet-name>AxisServlet</servlet-name>
+    <display-name>Apache-Axis Servlet</display-name>
+    <servlet-class>
+        org.apache.axis.transport.http.AxisServlet
+    </servlet-class>
+  </servlet>
+
+  <servlet>
+    <servlet-name>AdminServlet</servlet-name>
+    <display-name>Axis Admin Servlet</display-name>
+    <servlet-class>
+        org.apache.axis.transport.http.AdminServlet
+    </servlet-class>
+    <load-on-startup>100</load-on-startup>
+  </servlet>
+
+  <servlet>
+    <servlet-name>SOAPMonitorService</servlet-name>
+    <display-name>SOAPMonitorService</display-name>
+    <servlet-class>
+        org.apache.axis.monitor.SOAPMonitorService
+    </servlet-class>
+    <init-param>
+      <param-name>SOAPMonitorPort</param-name>
+      <param-value>5001</param-value>
+    </init-param>
+    <load-on-startup>100</load-on-startup>
+  </servlet>
+    <!-- Define mappings that are used by the servlet container to
+         translate a particular request URI (context-relative) to a
+         particular servlet.  The examples below correspond to the
+         servlet descriptions above.  Thus, a request URI like:
+
+           http://localhost:8080/{contextpath}/graph
+
+         will be mapped to the "graph" servlet, while a request like:
+
+           http://localhost:8080/{contextpath}/saveCustomer.do
+
+         will be mapped to the "controller" servlet.
+
+	 Note: context path is determined by the servlet container - 
+	 in Tomcat, specified in server.xml -kjdon
+         You may define any number of servlet mappings, including zero.
+         It is also legal to define more than one mapping for the same
+         servlet, if you wish to.
+    -->
+    <!--
+    <servlet-mapping>
+      <servlet-name>controller</servlet-name>
+      <url-pattern>*.do</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+      <servlet-name>graph</servlet-name>
+      <url-pattern>/graph</url-pattern>
+    </servlet-mapping>
+    -->
+  
+  <servlet-mapping>
+    <servlet-name>tester</servlet-name>
+    <url-pattern>/testing</url-pattern>
+  </servlet-mapping>
+  
+  <servlet-mapping>
+    <servlet-name>library</servlet-name>
+    <url-pattern>/library</url-pattern>
+  </servlet-mapping>
+  
+  <servlet-mapping>
+    <servlet-name>gateway</servlet-name>
+    <url-pattern>/gateway</url-pattern>
+  </servlet-mapping>
+  
+  <servlet-mapping>
+    <servlet-name>classic-library</servlet-name>
+    <url-pattern>/classic</url-pattern>
+  </servlet-mapping>
+  
+  <!-- axis mappings -->
+  <servlet-mapping>
+    <servlet-name>AxisServlet</servlet-name>
+    <url-pattern>/servlet/AxisServlet</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>AxisServlet</servlet-name>
+    <url-pattern>*.jws</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>AxisServlet</servlet-name>
+    <url-pattern>/services/*</url-pattern>
+  </servlet-mapping>
+
+  <!-- uncomment this if you want to use the SOAPMonitorService. You will also 
+  need to copy the SOAPMonitorApplet*.class files from 
+  gsdl3/comms/soap/axis/web/WEB-INF/classes to the gsdl3/web directory. See the 
+  comms/soap/axis/docs/install.html Appendix for details about how to use this -->
+  <!--
+  <servlet-mapping>
+    <servlet-name>SOAPMonitorService</servlet-name>
+    <url-pattern>/SOAPMonitor</url-pattern>
+  </servlet-mapping>
+  -->
+  <!-- uncomment this if you want the admin servlet -->
+  <!--
+  <servlet-mapping>
+    <servlet-name>AdminServlet</servlet-name>
+    <url-pattern>/servlet/AdminServlet</url-pattern>
+  </servlet-mapping>
+  -->
+
+  <!-- Define the default session timeout for your application,
+  in minutes.  From a servlet or JSP page, you can modify
+  the timeout for a particular session dynamically by using
+  HttpSession.getMaxInactiveInterval(). -->
+
+  <session-config>
+    <session-timeout>30</session-timeout>    <!-- 30 minutes -->
+  </session-config>
+
+  <!-- axis mime-mappings -->
+  <mime-mapping>
+    <extension>wsdl</extension>
+    <mime-type>text/xml</mime-type>
+  </mime-mapping>
+  
+  <mime-mapping>
+    <extension>xsd</extension>
+    <mime-type>text/xml</mime-type>
+  </mime-mapping>
+  
+</web-app>
+
+
Index: /greenstone3/trunk/web/gs_ajax_utils.js
===================================================================
--- /greenstone3/trunk/web/gs_ajax_utils.js	(revision 14125)
+++ /greenstone3/trunk/web/gs_ajax_utils.js	(revision 14125)
@@ -0,0 +1,129 @@
+
+
+function loadAsync(sUri, SOAPMessage) {
+   var xmlHttp = XmlHttp.create();
+   var async = true;
+   xmlHttp.open("POST", sUri, async);
+   xmlHttp.onreadystatechange = function () {
+      if (xmlHttp.readyState == 4){
+		var result = xmlHttp.responseText;
+			getTitle2(xmlHttp.responseXML, xmlHttp.responseText);
+    }     
+   }
+   xmlHttp.setRequestHeader("SOAPAction", " ");
+   xmlHttp.setRequestHeader("Content-Type", "Content-Type: text/xml; charset=utf-8");
+ 
+   xmlHttp.send(SOAPMessage);
+}
+
+
+function messageToSOAP(message) {
+    soapBody = '<soapenv:Body>' + message + '</soapenv:Body>'
+    soap = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' + soapBody + '</soapenv:Envelope>'
+    x= '<?xml version="1.0" encoding="UTF-8"?>' + soap;
+    return x;
+}
+
+
+
+
+function getText(element) { //get the text from possibly multiple text nodes
+if (element.hasChildNodes()) {
+	tempString = '';
+    for (j=0; j < element.childNodes.length; j++) {
+    				if (element.childNodes[j].nodeType == Node.TEXT_NODE ) { // =2
+    					tempString += element.childNodes[j].nodeValue;
+    				} 
+					else {
+						tempString += 'non text node: ';
+					}
+    } 
+	return tempString;
+}
+else {
+	return 'getText: element has no ChildNodes from which to extract Text';
+}
+}
+
+
+function newOpenTag(name) {
+	return '<' + name + '>';
+}
+
+function newCloseTag(name) {
+	return '</' + name + '>';
+}
+
+function newEmptyTag(name) {
+	return '<' + name + '/>';
+}
+
+function newElement(name, content) {
+    e = '<' + name + '>' + content;
+    e += '</' + name + '>';
+    return e;
+}
+
+
+function newElementAtt1(name, content, attName, attValue) {
+    e = '<' + name + ' ' + attName + '="' + attValue +'">' + content;
+    e += '</' + name + '>';
+    return e;
+}
+
+
+
+
+function newElementAtt(name, content, nameArray, valueArray) {
+    e = '<' + name + ' ' ;
+    for (i=0; i < nameArray.length; i++) {
+        e += newAttribute(nameArray[i], valueArray[i])
+    }
+    e += '>' + content;
+    e += '</' + name + '>';
+    return e;
+}
+
+
+function newAttribute(name, value) {
+				 return ' ' + name + '="' + value + '"';
+}
+
+/*
+var a = [];
+var b = [];
+a[0] = 'title';
+b[0] = 'test';
+a[1] = 'title2';
+b[1] = 'test2';
+
+alert( newElement('message', 'some content', a=[], b=[]));
+
+*/
+
+function countElementChildren(node) {
+  	count= 0;
+	childList = node.childNodes;
+	for(var i=0; i < (childList.length); i++) {
+		childNode = childList.item(i);
+		if ((childNode.nodeType == 1))	{ // only count elements
+				count++;
+		}
+	}
+	return count;
+}
+
+function removeAllChildren(node) {
+	while (node.hasChildNodes()) {
+		node.removeChild(node.firstChild);
+	}
+}
+
+
+function isElement(node) {
+    if (node.nodeType == 1) {
+    		return true; }
+    else {
+    		return false;
+    }
+}
Index: /greenstone3/trunk/web/index.html
===================================================================
--- /greenstone3/trunk/web/index.html	(revision 14125)
+++ /greenstone3/trunk/web/index.html	(revision 14125)
@@ -0,0 +1,47 @@
+<html>
+
+  <head>
+    <meta http-equiv="Content-Type"
+      content="text/html; charset=iso-8859-1">
+      <title>Greenstone Version 3</title>
+  </head>
+  
+  <body bgcolor="#ffffff" text="#000000" link="#006666" 
+    alink="#cc9900" vlink="#666633" background="interfaces/default/images/chalk.gif">
+    
+    <!-- page banner (_style:pagebanner_) -->
+    <center>
+      <table width=537 cellspacing=0 cellpadding=0>
+	<tr valign=top>
+	  <td rowspan=2 align=left><center><img src="interfaces/default/images/gsdlhead.gif" width=300 height=100 alt="Greenstone Digital Library Software"></center></td>
+	  <td align=right></td>
+	</tr>
+	
+	<tr>
+	  <td align=right></td>
+	</tr>
+	
+	<tr>
+	  <td colspan=2></td>
+	</tr>
+      </table>
+    </center>
+    <!-- end of page banner -->
+    
+    <center>
+      
+      <table width=537>
+	<tr><td><h3>Hello! Welcome to your Greenstone3 installation</h3></td></tr>
+	<tr><td>&nbsp;</td></tr>
+	<tr><td>What do you want to do today?</td></tr>
+	<tr><td>&nbsp;</td></tr>
+	
+	
+	<tr><td><a href="testing">Run</a> the test servlet</td></tr>
+	<tr><td><a href="library">Run</a> the standard library servlet. View the demo collections that come with Greenstone, using the default look and feel.</td></tr>
+	<tr><td><a href="classic">Run</a> the 'classic' servlet. View the same collections using the 'classic' (or Greenstone 2) look and feel.</td></tr>
+	<tr><td><a href="gateway">Run</a> the gateway servlet. This uses the standard look and feel, and talks via SOAP to the site with demo collections (localsite). Note that SOAP needs to be installed, and a SOAP server needs to be running for localsite.</td></tr>
+      </table>
+    </center>
+  </body>
+</html>
Index: /greenstone3/trunk/web/interfaces/classic/interfaceConfig.xml
===================================================================
--- /greenstone3/trunk/web/interfaces/classic/interfaceConfig.xml	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/classic/interfaceConfig.xml	(revision 14125)
@@ -0,0 +1,21 @@
+<interfaceConfig baseInterface="default">
+  <actionList>
+    <action name='p' class='PageAction'>
+      <subaction name='home' xslt='home.xsl'/>
+      <subaction name='about' xslt='about.xsl'/>
+      <subaction name='help' xslt='help.xsl'/>
+      <subaction name='pref' xslt='pref.xsl'/>
+      <subaction name='nav' xslt='nav.xsl'/>
+      <subaction name="html" xslt="html.xsl"/>
+    </action>
+    <action name='q' class='QueryAction' xslt='query.xsl'/>
+    <action name='b' class='GS2BrowseAction' xslt='classifier.xsl'/>
+    <action name='a' class='AppletAction' xslt='applet.xsl'/>
+    <action name='d' class='DocumentAction' xslt='document.xsl'/>
+    <action name='pr' class='ProcessAction' xslt='process.xsl'/>
+    <action name='s' class='SystemAction' xslt='system.xsl'/>
+  </actionList>
+  <languageList>
+    <language name='en' displayname='English' default_encoding='utf-8'/>
+  </languageList>
+</interfaceConfig>
Index: /greenstone3/trunk/web/interfaces/classic/style/classic.css
===================================================================
--- /greenstone3/trunk/web/interfaces/classic/style/classic.css	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/classic/style/classic.css	(revision 14125)
@@ -0,0 +1,220 @@
+/* classic stylesheet for greenstone3 */
+
+
+a:link { color: #006666; } 
+
+a:hover { color: #cc9900; }
+
+a:visited { color: #666633; } 
+
+
+.bgimage { background-image: url("../images/chalk.gif"); }
+
+/* this contains everything - all the other divs */
+#page {
+  margin: 0 3em 0 5em;
+  padding: 0;
+}
+
+#banner {
+  margin: 0 0 5px 0;
+  padding:0;
+ 
+}
+
+/* this div contains the bannerlinks and bannertitle paragraphs */
+div.pageinfo {
+  float: right;
+  text-align: right;
+  padding: 0;
+  margin:0 0 3px 0;	
+  width: 50%;
+}
+
+/* home, help, preferences links */
+p.bannerlinks {
+  font-family: sans-serif, arial, helvetica;
+  font-size: 10pt;
+  font-weight: bold;
+  margin:0;
+  padding:0;
+}
+
+/* the title set by the receptionist based on the page action */
+p.bannertitle {
+  font-family: sans-serif, arial, helvetica;
+  font-size: 24px;
+  font-weight: bold;
+  margin: 10px 0 0 0;
+  text-transform: lowercase;
+  white-space: nowrap;
+  padding: 6px 2px 10px 0px;
+  background-repeat: repeat-y;
+  background-position: top right; 
+  background-image: url("../images/banner_bg.png");  
+ 
+ }
+
+
+/* home, help, preferences links */
+p.bannerlinks {
+  font-family: sans-serif, arial, helvetica;
+  font-size: 10pt;
+  font-weight: bold;
+  margin:0;
+  padding:0;
+}
+
+/* the image for the collection, shown in the banner */
+div.collectimage {
+  text-align: left;
+  #height: 100%; /* for IE5/6 to make containing div the full height */
+  float: left;
+  width: 45%;
+  padding:0;
+  margin:0;
+}
+
+p.collectiontitle {
+  font-family: sans-serif, arial, helvetica;
+  font-size: 24px;
+  font-weight: bold;
+  text-transform: lowercase;
+  white-space: nowrap;
+  padding: 8px 0px 12px 2px;
+  background-repeat: repeat-y;
+  background-position: top left; 
+  margin:0;
+}
+
+a.collectiontitle {
+  color: black;
+  text-decoration: none;
+}
+
+/* make sure this is shown under the other divs (which may be floating) */
+div.bannerextra {
+   clear: both;
+}
+
+/* bg image set in style macro */
+div.divbar { /* for "select a collection" */
+  background-image: url("../images/bg_green.png"); 
+  font-family: arial;
+  font-size: 10pt;
+  font-weight: bold;
+  border: 0;
+  width: 100%; /* for ns4 */
+}
+
+/* bg image set in style macro */
+div.navbar {
+  background-image: url("../images/bg_green.png"); 	
+  min-width: 500px;
+  white-space: nowrap;
+  font-family: sans-serif, arial, helvetica;
+  font-size: 10pt;
+  font-weight: bold;
+  text-transform: lowercase;
+  border: 0;
+  width: 100%; /* for ns4 */
+}
+
+
+p.navbar { /* opt navbar text inside a divbar div */
+  text-align: center; 
+  margin: 0;
+  padding: 0;	
+}
+
+/* bg image set in style macro */
+a.navlink {
+  vertical-align: top; 
+  padding: 0 10px; 
+  color: black;
+  text-decoration: none;
+  background-image: url("../images/bg_off.png");
+  margin: 0 0 0 20px;
+}
+
+/* bg image set in style macro */
+a.navlink_sel {
+  vertical-align: top;
+  padding: 0 10px;
+  color: black;
+  text-decoration: none;
+  background-image: url("../images/bg_green.png"); 	
+}
+
+a.navlink:visited {
+  color: black;
+}
+
+/* for the nav_ns4.dm macro only (for netscape4 support) */
+a.navlink_ns4 {
+  background-color: #e8d9b1;
+}
+
+a.navlink:hover { 
+   background-image: url("../images/bg_on.png");
+ }
+
+span.narspace{
+  padding:0;
+  margin: 0 0 0 20px;		
+}
+
+div.document {
+  padding: 5px 0 0 0;
+  margin:0;
+}
+
+span.textselect { white-space: nowrap; }
+
+div.documenttext { clear: both; } /* come after any floating divs */
+
+div.heading_title {
+ font-size: 16pt;
+ font-weight: bold;
+
+} /* alternate to cover image */
+
+div.heading_image { float: left; } /* optional cover image */
+
+div.document div.buttons {
+   /* anything that holds buttons... toc_buttons but also continue button */
+   width: 100px; /* each button (inside its own div) can overflow this */
+}
+
+div#toc_buttons { /* expand/contract etc "buttons" */
+  clear: left; /* don't put next to another float on our left-hand side */
+  float: left;
+  margin: 0 15px 5px 0; 
+}
+
+div.button {
+  font-size: 11px;
+  font-weight: bold;
+  line-height: 1.2em;
+  /*background: #ffeecc; */
+  background: #f7e7c5;
+  margin: 1px;
+  border: 1px solid #eeddbb;
+  text-align: center;
+  vertical-align: middle;
+  height: 30px; /* IE6 and NS4 treat width/height as min-width/min-height */
+  width: 110px;
+}
+
+*>div.button { /* for other browsers - IE6 doesn't apply this */
+  height: auto;
+  width: auto;
+  min-height: 30px; 
+  min-width: 110px;
+}
+
+span.button {}
+span.button a { text-decoration: none; color: black; }
+span.button a:hover { /* IE6 doesn't do :hover for things that aren't <A> */
+  background: #eeddbb;
+}
Index: /greenstone3/trunk/web/interfaces/classic/style/classic2.css
===================================================================
--- /greenstone3/trunk/web/interfaces/classic/style/classic2.css	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/classic/style/classic2.css	(revision 14125)
@@ -0,0 +1,29 @@
+ul {
+  margin:0;
+  padding:0; 
+  list-style-type: none; 
+}
+
+ul li{
+  margin:0;
+  padding:0;
+  display: inline;
+}
+
+ul#resultlist li{
+  display:block;
+}
+
+
+ul#classifiernodelist li{
+  list-style: none;
+  margin: 0;
+  padding: 0;
+  display: block;
+}
+
+ul.childrenlist{
+  margin: 0 0 0 20px ;
+  padding: 0;
+  display: block;
+}
Index: /greenstone3/trunk/web/interfaces/classic/transform/about.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/classic/transform/about.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/classic/transform/about.xsl	(revision 14125)
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+
+  <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+  <xsl:include href="help-common.xsl"/>
+  <xsl:include href="query-common.xsl"/>
+  <xsl:include href="service-params.xsl"/>
+  <xsl:output method="html"/>  
+
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="/page/pageResponse/collection/displayItem[@name='name']"/>  
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName" select="/page/pageRequest/paramList/param[@name='c']/@value"/>
+      <xsl:apply-templates select="collection"><xsl:with-param name="collName" select="$collName"/></xsl:apply-templates>
+
+  </xsl:template>
+
+  <xsl:template match="collection">
+    <xsl:param name="collName"/>
+    <xsl:call-template name="standardPageBanner">
+      <xsl:with-param name="collName" select="$collName"/>
+      <xsl:with-param name="pageType">about</xsl:with-param>
+    </xsl:call-template>
+    <xsl:call-template name="navigationBar">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+    <div class="document">
+    <xsl:if test="/page/pageRequest/paramList/param[@name='ct']/@value = 0">
+    <xsl:apply-templates select="serviceList/service[@name='TextQuery']">
+      <xsl:with-param name="collName" select="$collName"/></xsl:apply-templates>
+    <xsl:call-template name="dividerBar"/>
+    </xsl:if>
+    </div>
+    <div>
+    <xsl:if test="displayItem[@name='description']">
+    <h3><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'about.aboutcoll')"/></h3>
+    <p><xsl:value-of select="displayItem[@name='description']" disable-output-escaping='yes'/></p>
+    </xsl:if>
+    <xsl:apply-templates select="." mode="simplehelp"/>
+    </div>	
+  </xsl:template>
+
+</xsl:stylesheet>  
+
Index: /greenstone3/trunk/web/interfaces/classic/transform/applet.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/classic/transform/applet.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/classic/transform/applet.xsl	(revision 14125)
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+  
+  <xsl:include href="style.xsl"/>
+  
+  <xsl:output method="html"/>  
+
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="pageResponse/service/applet"/>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName"><xsl:value-of select="../pageRequest/paramList/param[@name='c']/@value"/></xsl:variable>
+    <center>
+      <xsl:call-template name="standardPageBanner">
+	<xsl:with-param name="collName" select="$collName"/>
+	<xsl:with-param name="pageType"><xsl:choose><xsl:when test="service[@name='PhindApplet']">phrases</xsl:when><xsl:otherwise>applet</xsl:otherwise></xsl:choose></xsl:with-param>
+      </xsl:call-template>
+      <p/>
+    <xsl:call-template name="navigationBar">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>      
+<!--      <xsl:call-template name="dividerBar">
+	<xsl:with-param name="text" select="service/displayItem[@name='name']"/>
+      </xsl:call-template>-->
+      <p/>
+      <xsl:copy-of select="service/applet"/>
+      <xsl:call-template name="dividerBar"/>
+    </center>
+  </xsl:template>
+</xsl:stylesheet>  
+
Index: /greenstone3/trunk/web/interfaces/classic/transform/classifier.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/classic/transform/classifier.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/classic/transform/classifier.xsl	(revision 14125)
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+  
+  <xsl:include href="style.xsl"/>
+  <xsl:include href="classifiertools.xsl"/>
+  
+  <xsl:output method="html"/>  
+
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'nzdl')"/>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName"><xsl:value-of select="/page/pageRequest/paramList/param[@name='c']/@value"/></xsl:variable>
+    <xsl:variable name="serviceName"><xsl:value-of select="service/@name"/></xsl:variable>
+    <xsl:variable name="cl" select="/page/pageRequest/paramList/param[@name='cl']/@value"/>
+    <xsl:variable name="clTop">
+      <xsl:choose>
+	<xsl:when test="contains($cl, '.')"><xsl:value-of select="substring-before($cl, '.')"/></xsl:when>
+	<xsl:otherwise>
+	  <xsl:value-of select="$cl"/>
+	</xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+      <xsl:call-template name="standardPageBanner">
+	<xsl:with-param name="collName" select="$collName"/>
+	<xsl:with-param name="pageType">browse</xsl:with-param>
+	<xsl:with-param name="clTop" select="$clTop"/>
+      </xsl:call-template>
+      <xsl:call-template name="navigationBar">
+	<xsl:with-param name="collName" select="$collName"/>
+	<xsl:with-param name="clTop" select="$clTop"/>
+      </xsl:call-template>      
+      <div class="document">
+      <xsl:apply-templates select="classifier">
+	<xsl:with-param name="collName" select="$collName"/>
+	<xsl:with-param name="serviceName" select="$serviceName"/>
+      </xsl:apply-templates>
+      </div>
+  </xsl:template>
+  
+
+</xsl:stylesheet>
+
+
+
+
+
+
Index: /greenstone3/trunk/web/interfaces/classic/transform/document.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/classic/transform/document.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/classic/transform/document.xsl	(revision 14125)
@@ -0,0 +1,412 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util gsf">
+
+  <xsl:include href="style.xsl"/>
+  <xsl:include href="service-params.xsl"/>
+  <xsl:output method="html"/>
+
+  <!-- the main page layout template is here -->
+  <!-- override the one in style so we can display the doc over the whole page and get rid of the green bar down the side --> 
+  <xsl:template match="page" priority='2'>
+    <html>
+      <xsl:call-template name="pageHead"/>
+      <body>
+        <div id="page">
+           <xsl:apply-templates select="pageResponse"/>
+	   <xsl:call-template name="greenstoneFooter"/>
+	</div>  
+       </body>
+    </html>
+  </xsl:template>
+  
+  <xsl:template name="pageTitle">
+    <xsl:variable name="docID" select="/page/pageResponse/document/@selectedNode"/>
+    <xsl:for-each select='/page/pageResponse/document/descendant::documentNode[@nodeID=$docID]/ancestor-or-self::documentNode'><xsl:if test='position()!=1'>::</xsl:if><xsl:value-of select="metadataList/metadata[@name='Title']"/></xsl:for-each>
+  </xsl:template>
+
+  <!-- this is hard coded for GATE, should somehow do it dynamically-->
+  <xsl:template name="pageStyle">
+    <style type="text/css">
+      <xsl:text disable-output-escaping="yes">
+	span.Location {  display:inline; color : red }
+	span.Person {  display:inline; color : green }
+	span.Organization {  display:inline; color : yellow }
+	span.Date {  display:inline; color : blue }
+	span.query_term {display: inline; background-color : yellow }
+      </xsl:text>
+    </style>
+  </xsl:template>
+  
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName"><xsl:value-of select="/page/pageRequest/paramList/param[@name='c']/@value"/></xsl:variable>
+    <xsl:call-template name="standardPageBanner">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+    <xsl:call-template name="navigationBar">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+    <div class="document">     
+    <!-- display the document -->
+    <xsl:apply-templates select="document">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:apply-templates>
+   </div>
+  </xsl:template>
+	
+  <xsl:template match="document">
+    <xsl:param name="collName"/>
+    
+    <xsl:call-template name="documentHeading">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+    
+    <xsl:call-template name="documentContent">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template name="documentHeading">
+    <xsl:param name="collName"/>
+    <xsl:variable name="doCoverImage" select="/page/pageResponse/format/gsf:option[@name='coverImages']/@value"/>
+    <xsl:variable name="doTOC" select="/page/pageResponse/format/gsf:option[@name='documentTOC']/@value"/>
+    <xsl:variable name="p.a" select="/page/pageRequest/paramList/param[@name='p.a']/@value"/>
+    <xsl:variable name="p.sa" select="/page/pageRequest/paramList/param[@name='p.sa']/@value"/>
+    <xsl:variable name="p.s" select="/page/pageRequest/paramList/param[@name='p.s']/@value"/>
+    <div class="heading_image">
+       <xsl:if test="string($doCoverImage) != 'false' and (@docType='paged' or @docType='hierarchy')">
+	<xsl:call-template name="coverImage"/> 
+       </xsl:if>
+    </div>
+    <div class="buttons" id="toc_buttons">
+        <xsl:call-template name="documentButtons">
+	    <xsl:with-param name="collName" select="$collName"/>
+	</xsl:call-template>
+    </div>
+
+    <!--<div><xsl:call-template name="enrichServices">
+	    <xsl:with-param name="collName" select="$collName"/>
+	  </xsl:call-template></div>-->
+
+    <div class="toc">
+        <table class="v_list"><tr valign="top"><td valign="top"> <a href="{$library_name}?a={$p.a}&amp;sa={$p.sa}&amp;s={$p.s}&amp;c={$collName}&amp;rt=r"><xsl:call-template name="openbookimg"><xsl:with-param name="title">Close this book and return to search/browse</xsl:with-param>
+	  </xsl:call-template></a></td><td valign="top"></td>
+         <td valign="top">
+ 	    <xsl:choose><xsl:when test="@docType='simple'"><xsl:value-of select="metadataList/metadata[@name='Title']" disable-output-escaping="yes"/></xsl:when><xsl:otherwise><xsl:value-of select="documentNode/metadataList/metadata[@name='Title']" disable-output-escaping="yes"/></xsl:otherwise></xsl:choose>
+          </td></tr>
+         </table>
+        <xsl:if test="string($doTOC) != 'false'">
+	  <table><tr valign="top"><td><img alt="" src="/gsdl/images/space.gif" width="25"/></td><td><table class="v_list">
+	    <xsl:call-template name="TOC">
+	      <xsl:with-param name="collName" select="$collName"/>
+	    </xsl:call-template>
+	    </table>
+          </td></tr></table>
+	</xsl:if>  	 	   
+      </div>
+   </xsl:template>
+
+  <xsl:template name="coverImage">
+    <img alt="" onError="src='interfaces/classic/images/blank.gif'"><xsl:attribute name='src'><xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/>/index/assoc/<xsl:value-of select="metadataList/metadata[@name='archivedir']"/>/cover.jpg</xsl:attribute></img>
+  </xsl:template>
+
+  <xsl:template name="documentButtons">
+    <xsl:param name="collName"/>
+    <xsl:variable name="docID" select="/page/pageRequest/paramList/param[@name='d']/@value"/>
+    <xsl:variable name="sib" select="/page/pageRequest/paramList/param[@name='sib']/@value"/>
+    <xsl:variable name="ec" select="/page/pageRequest/paramList/param[@name='ec']/@value"/>
+    <xsl:variable name="ed" select="/page/pageRequest/paramList/param[@name='ed']/@value"/>
+   
+   
+      <!-- expand document -->
+      <!-- this doesn't work with MG so comment it out for now -->      
+      <xsl:if test="@docType = 'hierarchy' or @docType = 'paged'">
+      <div class="button">
+        <span class="button">
+	  <xsl:choose><xsl:when test="string($ed)='1'">
+	      <a href="{$library_name}?a=d&amp;d={$docID}&amp;c={$collName}&amp;sib={$sib}&amp;ed=0"><xsl:attribute name="title"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'doc.contract_doc_tip')"/></xsl:attribute>
+		  <xsl:value-of disable-output-escaping='yes' select="util:getInterfaceText($interface_name, /page/@lang, 'doc.contract_doc_b')"/>
+	      </a>
+	    </xsl:when>
+	    <xsl:otherwise>
+	        <a href="{$library_name}?a=d&amp;d={$docID}&amp;c={$collName}&amp;sib={$sib}&amp;ed=1"><xsl:attribute name="title"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'doc.expand_doc_tip')"/></xsl:attribute>
+	   <xsl:value-of disable-output-escaping='yes' select="util:getInterfaceText($interface_name, /page/@lang, 'doc.expand_doc_b')"/>
+	      </a>
+	    </xsl:otherwise>
+	  </xsl:choose>
+         </span>
+	</div>
+      </xsl:if> 
+      
+      <!-- expand contents -->
+      <xsl:if test="@docType = 'hierarchy' and string(/page/pageResponse/format/gsf:option[@name='documentTOC']/@value) != 'false'">
+      <div class="button">
+        <span class="button">
+	  <xsl:choose><xsl:when test="string($ec)='1'">
+	      <a  href="{$library_name}?a=d&amp;d={$docID}&amp;c={$collName}&amp;sib={$sib}&amp;ec=0"><xsl:attribute name="title"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'doc.contract_contents_tip')"/></xsl:attribute>
+		 <xsl:value-of disable-output-escaping='yes' select="util:getInterfaceText($interface_name, /page/@lang, 'doc.contract_contents_b')"/>
+	      </a>
+	    </xsl:when>
+	    <xsl:otherwise>
+	      <a  href="{$library_name}?a=d&amp;d={$docID}&amp;c={$collName}&amp;sib={$sib}&amp;ec=1"><xsl:attribute name="title"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'doc.expand_contents_tip')"/></xsl:attribute>
+		<xsl:value-of disable-output-escaping='yes' select="util:getInterfaceText($interface_name, /page/@lang, 'doc.expand_contents_b')"/>
+	      </a>
+	    </xsl:otherwise>
+	  </xsl:choose>
+	 </span>
+	</div>
+      </xsl:if>
+      <!-- detach page -->
+      <xsl:variable name="paramList" select="/page/pageRequest/paramList"/>
+      <div class="button">
+        <span class="button">
+	  <a  target="_blank"><xsl:attribute name="href"><xsl:value-of select="$library_name"/>?a=d&amp;d=<xsl:value-of select="$docID"/>&amp;c=<xsl:value-of select="$collName"/>&amp;sib=<xsl:value-of select="$sib"/>&amp;dt=<xsl:value-of select="$paramList/param[@name='dt']/@value"/>&amp;ec=<xsl:value-of select="$paramList/param[@name='ec']/@value"/>&amp;et=<xsl:value-of select="$paramList/param[@name='et']/@value"/>&amp;p.a=<xsl:value-of select="$paramList/param[@name='p.a']/@value"/>&amp;p.s=<xsl:value-of select="$paramList/param[@name='p.s']/@value"/>&amp;p.sa=<xsl:value-of select="$paramList/param[@name='p.sa']/@value"/></xsl:attribute><xsl:attribute name="title"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'doc.detach_page_tip')"/></xsl:attribute>
+	    <xsl:value-of disable-output-escaping='yes' select="util:getInterfaceText($interface_name, /page/@lang, 'doc.detach_page_b')"/>
+	  </a>
+         </span>
+      </div>
+   </xsl:template>
+
+  <xsl:template name="TOC">
+    <xsl:param name="collName"/>
+    <xsl:choose>
+      <xsl:when test="@docType='hierarchy'">
+	<xsl:call-template name="hierarchicalContents">
+	  <xsl:with-param name="collName" select="$collName"/>
+	</xsl:call-template>
+      </xsl:when>
+      <xsl:when test="@docType='paged'">
+	<xsl:call-template name="pagedContents">
+	  <xsl:with-param name="collName" select="$collName"/>
+	</xsl:call-template>
+      </xsl:when>
+    </xsl:choose>
+  </xsl:template>
+    
+  <xsl:template name="hierarchicalContents">
+    <xsl:param name="collName"/>
+    <xsl:variable name="oc" select="/page/pageRequest/paramList/param[@name='oc']/@value"/>
+    <xsl:variable name="d" select="/page/pageRequest/paramList/param[@name='d']/@value"/>
+    <xsl:variable name="sib" select="/page/pageRequest/paramList/param[@name='sib']/@value"/>
+    <xsl:variable name="ec" select="/page/pageRequest/paramList/param[@name='ec']/@value"/>
+    <xsl:if test="documentNode[@nodeID]">
+	<tr valign='top'><td>
+	    <xsl:choose><xsl:when test="string($oc)='0'">
+		<a href="{$library_name}?a=d&amp;c={$collName}&amp;d={$d}&amp;sib={$sib}&amp;oc=1"><xsl:call-template name="closedfolderimg"><xsl:with-param name="title">open the table of contents</xsl:with-param></xsl:call-template></a>
+	      </xsl:when>
+	      <xsl:otherwise><a href="{$library_name}?a=d&amp;c={$collName}&amp;d={$d}&amp;sib={$sib}&amp;oc=0"><xsl:call-template name="openfolderimg"><xsl:with-param name="title">close the table of contents</xsl:with-param></xsl:call-template></a></xsl:otherwise></xsl:choose>
+	  </td><td>Table of Contents</td></tr>
+	<xsl:if test="string($oc)!='0'">
+	  <tr><td>&#160;</td><td>
+	      <table>
+		<xsl:for-each select="documentNode/documentNode[@nodeID]">
+		  <xsl:apply-templates select='.'><xsl:with-param name="collName" select="$collName"/><xsl:with-param name="ec" select="$ec"/></xsl:apply-templates>
+		</xsl:for-each>
+	      </table>
+	    </td></tr>
+	</xsl:if>
+    </xsl:if>
+  </xsl:template>
+  
+  <!-- each icon-title pair is a row in a table. children go in a table in another row -->
+  <xsl:template match="documentNode">
+    <xsl:param name="collName"/>
+    <xsl:param name="ec"/>
+    <!-- Display the appropriate image, depending on the node type -->
+    <tr><td valign="top">
+	<a><xsl:attribute name="href"><xsl:value-of select='$library_name'/>?a=d&amp;c=<xsl:value-of select='$collName'/>&amp;d=<xsl:value-of select='@nodeID'/><xsl:if test="documentNode">.pr</xsl:if><xsl:if test="@nodeType='leaf'">&amp;sib=1</xsl:if><xsl:if test="string($ec) = '1'">&amp;ec=1</xsl:if></xsl:attribute>
+	  <xsl:apply-templates select="." mode="displayNodeIcon"/>
+	</a>
+      </td>
+      
+      <!-- Display associated title, bolded if the node has content -->
+      <td valign="top">
+	<xsl:choose>
+	  <xsl:when test="nodeContent">
+	    <b><xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name='Title']"/></b>
+	  </xsl:when>
+	  <xsl:otherwise>
+	    <xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name='Title']"/>
+	  </xsl:otherwise>
+	</xsl:choose>
+      </td>
+    </tr>
+    <!-- Apply recursively to the children of this node -->
+    <xsl:if test="documentNode[@nodeID]">
+      <tr><td>&#160;</td><td><table>
+	    <xsl:apply-templates select="documentNode[@nodeID]">
+	      <xsl:with-param name="collName" select="$collName"/>
+	      <xsl:with-param name="ec" select="$ec"/>
+	      <!--<xsl:with-param name="depth" select="$depth + 1"/>-->
+	    </xsl:apply-templates>
+	  </table>
+	</td></tr>
+    </xsl:if>
+  </xsl:template>
+  
+  <!-- default content is to print the title and content of any documentNodes that have nodeContent -->
+  <xsl:template name="documentContent">
+    <div class="documenttext">
+      <xsl:choose>
+        <xsl:when test="@docType='simple'">
+	  <xsl:apply-templates select="nodeContent"/>
+	</xsl:when>
+        <xsl:otherwise>
+	  <xsl:apply-templates select="descendant-or-self::node()/documentNode" mode="content"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </div>
+  </xsl:template>
+  
+  <xsl:template match="documentNode" mode="content">
+    <xsl:if test="nodeContent and string(nodeContent)">
+      <xsl:if test="metadataList/metadata[@name='Title']">
+	<h3><xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name='Title']"/></h3>
+      </xsl:if>
+      <xsl:apply-templates select="nodeContent"/>
+      </xsl:if>
+    
+  </xsl:template>
+
+  <!-- the actual text/content -->
+  <xsl:template match="nodeContent">
+    <p/>
+    <xsl:for-each select="node()">
+      <xsl:choose>
+	<xsl:when test="not(name())"><xsl:value-of select="." disable-output-escaping="yes"/></xsl:when>
+	<xsl:otherwise><xsl:apply-templates select="."/></xsl:otherwise>
+      </xsl:choose>
+    </xsl:for-each>
+  </xsl:template>
+  
+  <!-- match any file nodes -->
+  <xsl:template match="file">
+    <xsl:variable name="httpPath" select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/>
+    <xsl:choose>
+      <xsl:when test="util:isImage(@mimeType)">
+	<img src="{$httpPath}/{@href}"/>
+      </xsl:when>
+      <xsl:otherwise>
+	<a href="{$httpPath}/{@href}"><xsl:value-of select="@href"/></a>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+  
+  <!-- match any link nodes -->
+  <xsl:template match="link">
+    <xsl:variable name="collName" select="/page/pageRequest/paramList/param[@name='c']/@value"/> 
+    <xsl:variable name="actionargs">
+      <xsl:choose>
+	<xsl:when test="@type='document'">a=d</xsl:when>
+	<xsl:when test="@type='query'">a=q&amp;s=<xsl:value-of select="@service"/>&amp;rt=r</xsl:when>
+	<xsl:otherwise>
+	  p
+	</xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="serviceargs">
+      <xsl:for-each select="param">&amp;s1.<xsl:value-of select="@name"/>=<xsl:value-of select="@value"/></xsl:for-each>
+  </xsl:variable>
+    <a href="{$library_name}?{$actionargs}&amp;c={$collName}{$serviceargs}"><xsl:value-of disable-output-escaping="yes" select="."/></a>
+  </xsl:template>
+
+  <!-- match any annotations and make them span elements -->
+  <xsl:template match="annotation">
+    <span class="{@type}"><xsl:value-of disable-output-escaping="yes" select="."/></span>
+  </xsl:template>
+  
+  <!-- paged naviagtion : INCOMPLETE!!-->
+  <xsl:template name="pagedContents">
+    <xsl:param name="collName"/>
+    <xsl:variable name="pos" select="nodeStructureInfo/info[@name='siblingPosition']/@value"/>
+    <xsl:variable name="length" select="nodeStructureInfo/info[@name='numSiblings']/@value"/>
+    <xsl:variable name="children" select="nodeStructureInfo/info[@name='numChildren']/@value"/>
+      <xsl:choose>
+	<xsl:when test="$pos=-1"><!-- a doc -->
+	  <tr valign="top">
+	    <td align="left">
+	    </td>
+	    <td align="center"><center>
+		<b><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'document.pages', $children)"/></b>
+	      </center></td>
+	    <td align="right">
+	      <a href="{$library_name}?a=d&amp;c={$collName}&amp;d={@selectedNode}.fc"><img src="interfaces/default/images/more.gif" border="0" align="absbottom" /></a>
+	    </td>
+	  </tr>
+	</xsl:when>
+	
+	<xsl:otherwise> <!-- an internal node -->	  
+	  <tr valign="top">
+	    <td align="left">
+	      <xsl:if test=" not ( $pos = 1 )">
+		<a href="{$library_name}?a=d&amp;c={$collName}&amp;d={@selectedNode}.ps"><img src="interfaces/default/images/less.gif" border="0" align="absbottom" /></a>
+	      </xsl:if>
+	    </td>
+	    <td align="center"><center>
+		<b><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'document.pageof', concat($pos, ';', $length))"/></b>
+	      </center></td>
+	    <td align="right">
+	      <xsl:if test=" not($pos = $length)">
+		<a href="{$library_name}?a=d&amp;c={$collName}&amp;d={@selectedNode}.ns"><img src="interfaces/default/images/more.gif" border="0" align="absbottom" /></a>
+	      </xsl:if>
+	    </td>
+	  </tr>
+	</xsl:otherwise>
+      </xsl:choose>
+      <tr valign="middle">
+	<td align='center' valign='top' colspan='3'>
+	  <form name="GotoForm" method="get" action="{$library_name}">
+	    <input type='hidden' name='a' value='d'/>
+	    <input type='hidden' name='c' value='{$collName}'/>
+	    <input type='hidden' name='d' value='{@selectedNode}'/>
+	    <input type="text" name="gp" size="3" maxlength="4"/>
+	    <input type="submit"><xsl:attribute name='value'><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'document.gotopage')"/></xsl:attribute></input>
+	  </form>
+	</td>
+      </tr>
+   </xsl:template>
+  
+  <xsl:template name="enrichServices">
+    <xsl:param name="collName"/>
+    <xsl:variable name="docID" select="/page/pageRequest/paramList/param[@name='d']/@value"/>
+    <xsl:variable name="request-params" select="/page/pageRequest/paramList"/>
+    <xsl:for-each select="../serviceList/service">
+      <table border='1' cellspacing='0'>
+	<tr><td>
+	    <p /><xsl:value-of select="displayItem[@name='name']"/><p/>
+	    <form name="EnrichForm" method="get" action="{$library_name}">
+	      <xsl:apply-templates select="paramList"/>
+	      <input type='hidden' name='a' value='d'/>
+	      <input type='hidden' name='d' value='{$docID}'/>
+	      <input type='hidden' name='c' value='{$collName}'/>
+	      <xsl:if test='$request-params/param[@name="sib"]'>
+		<input type='hidden' name='sib'><xsl:attribute name='value'><xsl:value-of select='$request-params/param[@name="sib"]/@value'/></xsl:attribute></input></xsl:if>
+	      <input type='hidden' name='s' value='{@name}'/>
+	      <input type='hidden' name='p.a'><xsl:attribute name='value'><xsl:value-of select='$request-params/param[@name="p.a"]'/></xsl:attribute></input>
+	      <input type='hidden' name='p.sa'><xsl:attribute name='value'><xsl:value-of select='$request-params/param[@name="p.sa"]'/></xsl:attribute></input>
+	      <input type='hidden' name='p.s'><xsl:attribute name='value'><xsl:value-of select='$request-params/param[@name="p.s"]'/></xsl:attribute></input>
+	      <input type='hidden' name='end' value='1'/>
+	      <input type="submit"><xsl:attribute name="value"><xsl:value-of select="displayItem[@name='submit']"/></xsl:attribute></input>
+	    </form>
+	  </td></tr>
+      </table>
+    </xsl:for-each>
+  </xsl:template>
+
+  <xsl:template match="paramList" mode="hidden">
+    <xsl:for-each select="param">
+      <input type='hidden' name='{@name}' value='{@value}'/><xsl:text>
+      </xsl:text>
+    </xsl:for-each>
+  </xsl:template>
+  
+</xsl:stylesheet>
+
+
+
+
Index: /greenstone3/trunk/web/interfaces/classic/transform/help-common.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/classic/transform/help-common.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/classic/transform/help-common.xsl	(revision 14125)
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+
+
+  <xsl:template match="collection" mode="simplehelp">
+    <xsl:variable name="longCollName"><xsl:value-of select="displayItem[@name='name']" disable-output-escaping='yes'/></xsl:variable>
+    <!--<xsl:variable name="numoptions">5</xsl:variable>-->
+    <xsl:variable name="has_search"><xsl:choose><xsl:when test="serviceList/service[@name='TextQuery']">1</xsl:when><xsl:otherwise>0</xsl:otherwise></xsl:choose></xsl:variable>
+    <xsl:variable name="has_phrase"><xsl:choose><xsl:when test="serviceList/service[@name='PhindApplet']">1</xsl:when><xsl:otherwise>0</xsl:otherwise></xsl:choose></xsl:variable>
+    <xsl:variable name="numoptions" select="count(serviceList/service[@name='ClassifierBrowse']/classifierList/classifier)"/>
+    <h3><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'help.simplehelpheading', $longCollName)"/></h3>
+    <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'help.numbrowseoptions', $numoptions+$has_search+$has_phrase)"/>
+    <ul>
+     <xsl:if test="$has_search =1">
+       <li><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'help.Searchshort')" disable-output-escaping='yes'/></li>
+     </xsl:if>
+     <xsl:for-each select="serviceList/service[@name='ClassifierBrowse']/classifierList/classifier">
+       <xsl:variable name="title">help.<xsl:value-of select="@content"/>short</xsl:variable>
+       <li><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, $title)" disable-output-escaping='yes'/></li>
+     </xsl:for-each>
+     <xsl:if test="$has_phrase =1">
+       <li><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'help.Phraseshort')" disable-output-escaping='yes'/></li>
+     </xsl:if>
+     </ul>
+     <xsl:if test="$has_search =1">
+       <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'help.Searchlong')" disable-output-escaping='yes'/>
+     </xsl:if>
+     <xsl:for-each select="serviceList/service[@name='ClassifierBrowse']/classifierList/classifier">
+       <xsl:variable name="title">help.<xsl:value-of select="@content"/>long</xsl:variable>
+       <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, $title)" disable-output-escaping='yes'/>
+     </xsl:for-each>
+     <xsl:if test="$has_phrase =1">
+       <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'help.Phraselong')" disable-output-escaping='yes'/>
+     </xsl:if>
+     
+  </xsl:template>
+
+   
+</xsl:stylesheet>
Index: /greenstone3/trunk/web/interfaces/classic/transform/help.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/classic/transform/help.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/classic/transform/help.xsl	(revision 14125)
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+
+  <xsl:include href="style.xsl"/>
+  <!--<xsl:include href="help-text.xsl"/>-->
+  <xsl:include href="page-common.xsl"/>
+  
+  <xsl:output method="html"/>  
+  
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'help_tip')"/>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName" select="/page/pageRequest/paramList/param[@name='c']/@value"/>
+    <center>
+      <xsl:call-template name="standardPageBanner">
+	<xsl:with-param name="collName" select="$collName"/>
+	<xsl:with-param name="pageType">help</xsl:with-param>
+      </xsl:call-template>
+      <xsl:call-template name="navigationBar">
+	<xsl:with-param name="collName" select="$collName"/>
+      </xsl:call-template>      
+      <p />Help text to go here!!
+    </center>
+  </xsl:template>
+
+
+</xsl:stylesheet>
Index: /greenstone3/trunk/web/interfaces/classic/transform/home.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/classic/transform/home.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/classic/transform/home.xsl	(revision 14125)
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+
+  <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+
+  <xsl:output method="html"/>  
+
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'gsdl')"/>
+  </xsl:template>
+  
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+  <xsl:template match="pageResponse">
+    <xsl:call-template name="greenstonePageBanner"/> 
+    <xsl:apply-templates select="collectionList"/>   
+  </xsl:template>
+
+  <xsl:template match="collectionList">
+    <xsl:for-each select="collection"> 
+      <xsl:variable name="ct"><xsl:choose><xsl:when test="metadataList/metadata[@name='buildType']='mgpp'">1</xsl:when><xsl:otherwise>0</xsl:otherwise></xsl:choose></xsl:variable>
+
+      <p>
+      <a href="{$library_name}?a=p&amp;sa=about&amp;c={@name}&amp;ct={$ct}">
+	  <img width="150" border="1">
+	    <xsl:attribute name="src">
+	      <xsl:value-of select="metadataList/metadata[@name='httpPath']"/>/images/<xsl:choose><xsl:when test="displayItem[@name='smallicon']"><xsl:value-of select="displayItem[@name='smallicon']"/></xsl:when><xsl:otherwise><xsl:value-of select="displayItem[@name='icon']"/></xsl:otherwise></xsl:choose>
+	    </xsl:attribute>
+	    <xsl:attribute name="alt">
+	      <xsl:value-of select="displayItem[@name='name']"/>
+	    </xsl:attribute>
+	  </img>
+	</a>
+      </p>
+    </xsl:for-each> 
+    <xsl:call-template name="collWarning"/>
+  </xsl:template> 
+  
+  <xsl:template name="collWarning">
+    <xsl:call-template name="dividerBar"/>	
+    <div>
+      <xsl:value-of select="util:getInterfaceText('classic', /page/@lang, 'home.coll_warning')"/>
+    </div>	
+   </xsl:template>
+</xsl:stylesheet>  
+
+
Index: /greenstone3/trunk/web/interfaces/classic/transform/nav.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/classic/transform/nav.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/classic/transform/nav.xsl	(revision 14125)
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+  
+   <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+
+  <xsl:output method="html"/>  
+  
+  <xsl:template match="page">
+    <html>
+      <head>
+	<title>
+	  <xsl:call-template name="pageTitle"/><xsl:text> </xsl:text>
+	</title>
+	<xsl:call-template name="globalStyle"/>
+	<base target="_top"/>
+      </head>
+      <body style="background-image: none;">
+	<center>
+	  <table width="537">
+	    <tr><td>
+		<xsl:apply-templates select="pageResponse"/>
+	      </td></tr>
+	  </table>
+	</center>
+      </body>
+    </html>
+  </xsl:template>
+
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="/page/pageResponse/*/displayItem[@name='name']"/>
+  </xsl:template>
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName" select="/page/pageRequest/paramList/param[@name='c']/@value"/>
+    <div align="right">
+    <xsl:call-template name="top-buttons">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+      </div>
+    <xsl:call-template name="navigationBar">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>      
+  </xsl:template>
+
+</xsl:stylesheet>
Index: /greenstone3/trunk/web/interfaces/classic/transform/pref.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/classic/transform/pref.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/classic/transform/pref.xsl	(revision 14125)
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+
+  <xsl:include href="style.xsl"/>
+  <!--<xsl:include href="pref-text.xsl"/>-->
+  
+  <xsl:output method="html"/>  
+  
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref_tip')"/>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName" select="/page/pageRequest/paramList/param[@name='c']/@value"/>
+    <center>
+      <xsl:call-template name="standardPageBanner">
+	<xsl:with-param name="collName" select="$collName"/>
+	<xsl:with-param name="pageType">pref</xsl:with-param>
+      </xsl:call-template>
+      <xsl:call-template name="navigationBar">
+	<xsl:with-param name="collName" select="$collName"/>
+      </xsl:call-template>
+      <form name="PrefForm" method="get" action="{$library_name}">
+	<input type='hidden' name='a' value='p'/>
+	<input type='hidden' name='sa' value='pref'/>
+	<table>
+	  <tr><td><h3><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref.prespref')"/></h3></td></tr>
+	  <tr><td><xsl:call-template name="pres-prefs"/></td></tr>
+	  <tr><td><xsl:call-template name="dividerBar"/></td></tr>
+	  <tr><td><h3><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref.searchpref')"/></h3></td></tr>
+	  <tr><td><xsl:call-template name="search-prefs"/></td></tr>
+	  <tr><td><xsl:call-template name="dividerBar"/></td></tr>
+	</table>
+      </form>
+    </center>
+  </xsl:template>
+
+  
+  <xsl:template name="pres-prefs">
+    <table>
+      <tr><td><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref.interfacelang')"/></td><td align='left'>English</td></tr>
+      <tr><td><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref.encoding')"/></td><td align='left'>UTF-8</td></tr>
+    </table>
+  </xsl:template>
+  
+  <xsl:template name="search-prefs">
+    <xsl:param name="ns">s1.</xsl:param>
+    <xsl:variable name="ct"><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name='ct']"><xsl:value-of select="/page/pageRequest/paramList/param[@name='ct']/@value"/></xsl:when><xsl:otherwise>0</xsl:otherwise></xsl:choose></xsl:variable>
+    <table>
+      <tr><td> </td><td> </td><td align='right'><input type='submit' value='set prefs'/></td></tr>
+      <xsl:choose>
+	<xsl:when test="$ct=0">
+	  <xsl:call-template name='text-search-prefs'/>
+	</xsl:when>
+	<xsl:otherwise>
+      <!-- search type -->
+	  <xsl:variable name='querytype'><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name='qt']"><xsl:value-of select="/page/pageRequest/paramList/param[@name='qt']/@value"/></xsl:when><xsl:otherwise>0</xsl:otherwise></xsl:choose></xsl:variable>
+	  <tr><td  rowspan='2' valign='baseline'>Type of search:</td><td><input type='radio' name='qt' value='0'><xsl:if test="$querytype=0"><xsl:attribute name="checked"></xsl:attribute></xsl:if></input></td><td align='left'> text search</td></tr>
+	  <tr><td></td><td>
+	      <table>
+		<xsl:call-template name='text-search-prefs'/>
+	      </table></td></tr>
+	  
+	  <tr><td> </td><td><input type='radio' name='qt' value='1'><xsl:if test="$querytype=1"><xsl:attribute name="checked"></xsl:attribute></xsl:if></input></td><td> form search<br /></td></tr>
+	  <tr><td></td><td></td><td>
+	      <table>
+		<!-- query form mode -->
+		<xsl:variable name="queryfmode"><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name='qfm']"><xsl:value-of select="/page/pageRequest/paramList/param[@name='qfm']/@value"/></xsl:when><xsl:otherwise>0</xsl:otherwise></xsl:choose></xsl:variable>
+		<tr><td valign='baseline'>Form type:</td><td><input type='radio' name='qfm' value='0'><xsl:if test="$queryfmode=0"><xsl:attribute name="checked"></xsl:attribute></xsl:if></input> simple <br />
+		    <input type='radio' name='qfm' value='1'><xsl:if test="$queryfmode=1"><xsl:attribute name="checked"></xsl:attribute></xsl:if></input> advanced</td></tr>
+		<!-- query form num boxes -->
+		<xsl:variable name="numbox"><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name='qfn']"><xsl:value-of select="/page/pageRequest/paramList/param[@name='qfn']/@value"/></xsl:when><xsl:otherwise>4</xsl:otherwise></xsl:choose></xsl:variable>
+		<tr><td colspan='2'>with <select name="qfn">
+		      <option value="2"><xsl:if test="$numbox=2"><xsl:attribute name="selected"></xsl:attribute></xsl:if>2</option> 
+		      <option value="4"><xsl:if test="$numbox=4"><xsl:attribute name="selected"></xsl:attribute></xsl:if>4</option>
+		      <option value="6"><xsl:if test="$numbox=6"><xsl:attribute name="selected"></xsl:attribute></xsl:if>6</option>
+		      <option value="8"><xsl:if test="$numbox=8"><xsl:attribute name="selected"></xsl:attribute></xsl:if>8</option>
+		    </select> fields</td></tr>
+	      </table></td></tr>
+	</xsl:otherwise>
+      </xsl:choose>
+      <!-- case folding -->
+      <xsl:variable name="casevar" select="concat($ns,'case')"/>
+      <xsl:variable name="case"><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name=$casevar]"><xsl:value-of select="/page/pageRequest/paramList/param[@name=$casevar]/@value"/></xsl:when><xsl:otherwise>1</xsl:otherwise></xsl:choose></xsl:variable>
+      <tr><td rowspan='2' valign='baseline'>Case differences:</td><td><input type='radio' name='{$ns}case' value='1'><xsl:if test="$case=1"><xsl:attribute name="checked"></xsl:attribute></xsl:if></input></td><td> ignore case differences</td></tr>
+      <tr><td><input type='radio' name='{$ns}case' value='0'><xsl:if test="$case=0"><xsl:attribute name="checked"></xsl:attribute></xsl:if></input></td><td> upper/lower case must match</td></tr>
+      <!-- stemming -->
+      <xsl:variable name="stemvar" select="concat($ns,'stem')"/>
+      <xsl:variable name="stem"><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name=$stemvar]"><xsl:value-of select="/page/pageRequest/paramList/param[@name=$stemvar]/@value"/></xsl:when><xsl:otherwise>0</xsl:otherwise></xsl:choose></xsl:variable>
+      <tr><td  rowspan='2' valign='baseline'>Word endings:</td><td><input type='radio' name='{$ns}stem' value='1'><xsl:if test="$stem=1"><xsl:attribute name="checked"></xsl:attribute></xsl:if></input></td><td> ignore word endings</td></tr>
+      <tr><td><input type='radio' name='{$ns}stem' value='0'><xsl:if test="$stem=0"><xsl:attribute name="checked"></xsl:attribute></xsl:if></input></td><td> whole word must match</td></tr>
+      <!-- hit display -->
+      <xsl:variable name="maxvar" select="concat($ns,'maxDocs')"/>
+      <xsl:variable name="maxdocs"><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name=$maxvar]"><xsl:value-of select="/page/pageRequest/paramList/param[@name=$maxvar]/@value"/></xsl:when><xsl:otherwise>50</xsl:otherwise></xsl:choose></xsl:variable>
+      <xsl:variable name="hits"><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name='hitsPerPage']"><xsl:value-of select="/page/pageRequest/paramList/param[@name='hitsPerPage']/@value"/></xsl:when><xsl:otherwise>20</xsl:otherwise></xsl:choose></xsl:variable>
+      <tr><td colspan='3'>Return up to 
+	  <select name="{$ns}maxDocs">
+	    <option value="50"><xsl:if test="$maxdocs=50"><xsl:attribute name="selected"></xsl:attribute></xsl:if>50</option>
+	    <option value="100"><xsl:if test="$maxdocs=100"><xsl:attribute name="selected"></xsl:attribute></xsl:if>100</option>
+	    <option value="200"><xsl:if test="$maxdocs=200"><xsl:attribute name="selected"></xsl:attribute></xsl:if>200</option>
+	    <option value="-1"><xsl:if test="$maxdocs=-1"><xsl:attribute name="selected"></xsl:attribute></xsl:if>all</option>
+	  </select>
+	  hits with 
+	  <select name="hitsPerPage">
+	    <option value="10"><xsl:if test="$hits=10"><xsl:attribute name="selected"></xsl:attribute></xsl:if>10 </option> 
+	    <option value="20"><xsl:if test="$hits=20"><xsl:attribute name="selected"></xsl:attribute></xsl:if>20</option>
+	    <option value="50"><xsl:if test="$hits=50"><xsl:attribute name="selected"></xsl:attribute></xsl:if>50</option>
+	    <option value="-1"><xsl:if test="$hits=-1"><xsl:attribute name="selected"></xsl:attribute></xsl:if>all</option>
+	  </select>
+	  hits per page.
+	</td></tr>
+    </table>
+  </xsl:template>
+
+  <xsl:template name="text-search-prefs">
+    <!-- query mode -->
+    <xsl:variable name="querymode"><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name='qm']"><xsl:value-of select="/page/pageRequest/paramList/param[@name='qm']/@value"/></xsl:when><xsl:otherwise>0</xsl:otherwise></xsl:choose></xsl:variable>
+    <tr><td rowspan='2' valign='baseline'>Query mode:</td><td><input type='radio' name='qm' value='0'><xsl:if test="$querymode=0"><xsl:attribute name="checked"></xsl:attribute></xsl:if></input></td><td> simple query mode</td></tr>
+	<tr><td><input type='radio' name='qm' value='1'><xsl:if test="$querymode=1"><xsl:attribute name="checked"></xsl:attribute></xsl:if></input></td><td> advanced query mode (allows boolean searching using !, &amp;, |, and parentheses)</td></tr>
+    
+    <!-- query box size -->
+    <xsl:variable name="boxsize"><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name='qb']"><xsl:value-of select="/page/pageRequest/paramList/param[@name='qb']/@value"/></xsl:when><xsl:otherwise>0</xsl:otherwise></xsl:choose></xsl:variable>
+    <tr><td rowspan='2' valign='baseline'>Query box size:</td><td><input type='radio' name='qb' value='0'><xsl:if test="$boxsize=0"><xsl:attribute name="checked"></xsl:attribute></xsl:if></input></td><td> regular query box</td></tr>
+	<tr><td><input type='radio' name='qb' value='1'><xsl:if test="$boxsize=1"><xsl:attribute name="checked"></xsl:attribute></xsl:if></input></td><td> large query box</td></tr>
+  </xsl:template>
+</xsl:stylesheet>
Index: /greenstone3/trunk/web/interfaces/classic/transform/query-common.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/classic/transform/query-common.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/classic/transform/query-common.xsl	(revision 14125)
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+
+  <!--<xsl:include href="service-params.xsl"/>-->
+  <xsl:template match="service">
+    <xsl:param name="collName"/>
+    <xsl:variable name="subaction" select="../pageRequest/@subaction"/>
+    <div class="queryform">
+     <p> 
+      <form name="QueryForm" method="get" action="{$library_name}">
+        <input type="hidden" name="a" value="q"/>
+        <input type="hidden" name="sa" value="{$subaction}"/>
+        <input type="hidden" name="rt" value="rd"/>
+        <input type="hidden" name="s" value="{@name}"/>
+        <input type="hidden" name="c" value="{$collName}"/>
+        <input type="hidden" name="startPage" value="1"/>
+      <xsl:apply-templates select="paramList"/>
+      </form>
+     </p> 
+    </div>
+  </xsl:template>
+  
+  <!-- a special handling of the param list - we override the one in service-params -->
+  <xsl:template match="paramList" priority='2'>
+    <span class="textselect">
+	  Search for <xsl:apply-templates select="param[@name='index']"><xsl:with-param name="default"><xsl:apply-templates select="param[@name='index']" mode="calculate-default"/></xsl:with-param></xsl:apply-templates><xsl:if test="param[@name='level']">at <xsl:apply-templates select="param[@name='level']"><xsl:with-param name="default"><xsl:apply-templates select="param[@name='level']" mode="calculate-default"/></xsl:with-param></xsl:apply-templates> level</xsl:if><xsl:call-template name='query_mode'/>
+    </span>	
+    <span class="querybox"> 
+     <xsl:call-template name="query-and-submit"/>
+    </span>
+  </xsl:template>
+  
+  <!-- new template for match mode -->
+  <xsl:template name='query_mode'>
+    <xsl:variable name="qt" select="/page/pageRequest/paramList/param[@name='qt']/@value"/>
+    <xsl:choose>
+      <xsl:when test="$qt=1">
+	<xsl:variable name="qfm" select="/page/pageRequest/paramList/param[@name='qfm']/@value"/>
+	<xsl:choose>
+	  <xsl:when test="$qfm=1">
+	    and display results in <xsl:apply-templates select="param[@name='sortBy']"><xsl:with-param name="default"><xsl:apply-templates select="param[@name='sortBy']" mode="calculate-default"/></xsl:with-param></xsl:apply-templates> order
+	  </xsl:when>
+	  <xsl:otherwise>
+	    which contain <xsl:apply-templates select="param[@name='matchMode']"><xsl:with-param name="default"><xsl:apply-templates select="param[@name='matchMode']" mode="calculate-default"/></xsl:with-param></xsl:apply-templates> of
+	  </xsl:otherwise>
+	</xsl:choose>
+      </xsl:when>
+      <xsl:otherwise>
+	<xsl:variable name="ct" select="/page/pageRequest/paramList/param[@name='ct']/@value"/>
+	<xsl:variable name="qm" select="/page/pageRequest/paramList/param[@name='qm']/@value"/>
+	<xsl:choose>
+	  <xsl:when test="$qm=1 and $ct=0">
+	    using ranked/bool query
+	  </xsl:when>
+	  <xsl:when test="$qm=1 and $ct=1">
+	    and display results in <xsl:apply-templates select="param[@name='sortBy']"><xsl:with-param name="default"><xsl:apply-templates select="param[@name='sortBy']" mode="calculate-default"/></xsl:with-param></xsl:apply-templates> order
+	  </xsl:when>
+	  <xsl:otherwise>
+	    which contain <xsl:apply-templates select="param[@name='matchMode']"><xsl:with-param name="default"><xsl:apply-templates select="param[@name='matchMode']" mode="calculate-default"/></xsl:with-param></xsl:apply-templates> of the words
+	  </xsl:otherwise>
+	</xsl:choose>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="param[@name='matchMode']" mode='query1'>
+   <xsl:param name='default'/>
+    <xsl:variable name="qfm" select="/page/pageRequest/paramList/param[@name='qfm']/@value"/>
+    <xsl:choose>
+      <xsl:when test="$qfm=1">
+	and display results in <xsl:apply-templates select="../param[@name='sortBy']"><xsl:with-param name="default" select="$default"/></xsl:apply-templates> order
+      </xsl:when>
+      <xsl:otherwise>
+	which contain <xsl:apply-templates select='.'><xsl:with-param name="default" select="$default"/></xsl:apply-templates> of the words
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+  
+  <xsl:template name="query-and-submit">
+    <xsl:variable name="qt" select="/page/pageRequest/paramList/param[@name='qt']/@value"/>
+    <xsl:choose>
+      <xsl:when test="$qt=1"> <!-- doing form query -->
+	<xsl:variable name="qfm" select="/page/pageRequest/paramList/param[@name='qfm']/@value"/>
+	<xsl:choose>
+	  <xsl:when test="$qfm=1">
+	     <xsl:apply-templates select="param[@name='complexField']"/>
+	  </xsl:when>
+	  <xsl:otherwise>
+	     <xsl:apply-templates select="param[@name='simpleField']"/>
+	  </xsl:otherwise>
+	</xsl:choose>
+	    <input type="submit"><xsl:attribute name="value"><xsl:value-of select="../displayItem[@name='submit']"/></xsl:attribute></input>
+	 
+      </xsl:when>
+      <xsl:otherwise> <!-- doing text query -->
+    <xsl:variable name="qb" select="/page/pageRequest/paramList/param[@name='qb']/@value"/>
+	<xsl:choose>
+	  <xsl:when test="$qb=1"><!-- large query box -->
+	       <textarea name="query" cols='63' rows='10'>
+		  <xsl:apply-templates select="param[@name='query']" mode="calculate-default"/><xsl:text> </xsl:text><!-- put a space here just in case there is no value- mozilla craps out if have a <textarea /> element -->
+		</textarea>
+	   <input type="submit"><xsl:attribute name="value"><xsl:value-of select="../displayItem[@name='submit']"/></xsl:attribute></input>
+	   </xsl:when>
+	  <xsl:otherwise>
+	 	<xsl:variable name="qs"><xsl:apply-templates select="param[@name='query']" mode="calculate-default"/></xsl:variable>
+		<nobr><xsl:apply-templates select="param[@name='query']"><xsl:with-param name="default" select="java:org.greenstone.gsdl3.util.XSLTUtil.tidyWhitespace($qs)"/></xsl:apply-templates><input type="submit"><xsl:attribute name="value"><xsl:value-of select="../displayItem[@name='submit']"/></xsl:attribute></input></nobr>
+	   </xsl:otherwise>
+	</xsl:choose>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+  
+  <!-- overwrite the multi param to use our value of occurs, not the one with the param -->
+  <xsl:template match="param[@type='multi']" priority='2'>
+    <xsl:variable name="parent" select="@name"/>
+    <table>
+      <tr>
+	<xsl:for-each select="param">
+	  <xsl:variable name='pname' select='@name'/>
+	  <td><xsl:value-of select="displayItem[@name='name']"/></td>
+	</xsl:for-each>
+      </tr>
+      <!-- the number of times to display this is the qfn variable -->
+      <xsl:variable name="numbox"><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name='qfn']"><xsl:value-of select="/page/pageRequest/paramList/param[@name='qfn']/@value"/></xsl:when><xsl:otherwise>4</xsl:otherwise></xsl:choose></xsl:variable>
+      <xsl:apply-templates select="." mode="contents"><xsl:with-param name="occurs" select="$numbox"/><xsl:with-param name="pos" select="0"/></xsl:apply-templates>
+    </table>
+  </xsl:template>
+
+  <xsl:template match="param[@type='multi']" mode="contents">
+    <xsl:param name="occurs"/>
+    <xsl:param name="pos"/>
+ <!--   <xsl:variable name="pos" select="@occurs - $occurs"/>-->
+    <tr><xsl:for-each select="param">
+	<xsl:variable name="pname" select="@name"/>
+	<xsl:variable name="values" select="/page/pageRequest/paramList/param[@name=$pname]/@value"/>
+	<td><xsl:choose>
+	    <xsl:when test="not(@ignore) or  @ignore != $pos">      
+	      <xsl:apply-templates select='.'><xsl:with-param name="default" select="java:org.greenstone.gsdl3.util.XSLTUtil.getNumberedItem($values, $pos)"/></xsl:apply-templates>
+	    </xsl:when>
+	    <xsl:otherwise><!-- put in a hidden placeholder -->
+	      <input type="hidden" name='{@name}' value=''/>
+	    </xsl:otherwise>
+	  </xsl:choose></td>
+      </xsl:for-each></tr> 
+    <!-- recursively call this template to get multiple entries -->
+    <xsl:if test="$pos &lt; ($occurs - 1)">
+      <xsl:apply-templates select="." mode="contents"><xsl:with-param name="occurs" select="$occurs"/><xsl:with-param name="pos" select="$pos+1"/></xsl:apply-templates>
+    </xsl:if>
+  </xsl:template>
+
+</xsl:stylesheet>
Index: /greenstone3/trunk/web/interfaces/classic/transform/query.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/classic/transform/query.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/classic/transform/query.xsl	(revision 14125)
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+
+  
+  <xsl:include href="style.xsl"/>
+  <xsl:include href="service-params.xsl"/>
+  <xsl:include href="querytools.xsl"/>
+  <xsl:include href="query-common.xsl"/>  
+  <xsl:output method="html"/>
+  
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'nzdl')"/>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName"><xsl:value-of select="/page/pageRequest/paramList/param[@name='c']/@value"/></xsl:variable>
+
+      <xsl:call-template name="standardPageBanner">
+	<xsl:with-param name="collName" select="$collName"/>
+	<xsl:with-param name="pageType">search</xsl:with-param>
+      </xsl:call-template>
+      <xsl:call-template name="navigationBar">
+	<xsl:with-param name="collName" select="$collName"/>
+      </xsl:call-template>      
+    <div class="document">
+     <xsl:apply-templates select="service">
+	<xsl:with-param name="collName" select="$collName"/>
+      </xsl:apply-templates>
+    <xsl:if test="documentNodeList">
+      <xsl:call-template name="query-response">
+	<xsl:with-param name="collName" select="$collName"/>
+      </xsl:call-template>
+    </xsl:if>
+   </div>
+  </xsl:template>
+  
+  <xsl:template name="query-response">
+    <xsl:param name="collName"/>
+    <xsl:call-template name="dividerBar">
+      <xsl:with-param name='text'><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'query.results')"/></xsl:with-param></xsl:call-template>
+
+    <!-- If query term information is available, display it -->
+    <xsl:call-template name="termInfo"/>    
+    <!-- If the number of matching documents is known, display it -->
+    <xsl:call-template name="matchDocs"/>
+    
+    <!-- Display the matching documents -->
+    <xsl:call-template name="resultList">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+    <!-- next and prev links at bottom of page -->
+    <xsl:call-template name="resultNavigation"/>
+  </xsl:template>
+
+</xsl:stylesheet>  
Index: /greenstone3/trunk/web/interfaces/classic/transform/style.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/classic/transform/style.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/classic/transform/style.xsl	(revision 14125)
@@ -0,0 +1,368 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+  
+  <!-- some global parameters - these are set by whoever is invoking the transformation -->
+  <xsl:param name="interface_name"/>
+  <xsl:param name="library_name"/>
+
+  <!-- the main page layout template is here -->
+  <xsl:template match="page">
+    <html>
+      <xsl:call-template name="pageHead"/>
+      <body class="bgimage">
+	<div id="page">
+	   <xsl:apply-templates select="pageResponse"/>
+	   <xsl:call-template name="greenstoneFooter"/>                	   
+	</div>
+      </body>
+    </html>
+  </xsl:template>
+
+  
+  <!-- put a space in the title in case the actual value is missing - mozilla will not display a page with no title-->
+  <xsl:template name="pageHead">
+    <head>
+      <title>
+	<xsl:call-template name="pageTitle"/><xsl:text> </xsl:text>
+      </title>
+      <xsl:call-template name="globalStyle"/>
+      <xsl:call-template name="pageStyle"/>
+    </head>
+  </xsl:template>
+
+  <!-- any global style stuff should go in here -->
+  <xsl:template name="globalStyle">
+    <link rel="stylesheet" href="interfaces/classic/style/classic.css" type="text/css"/>
+     <link rel="stylesheet" href="interfaces/classic/style/classic2.css" type="text/css"/>
+  </xsl:template>
+  
+  <xsl:template name="greenstonePageBanner">
+     <div id="banner">
+        <div class="collectimage">
+            <img src="interfaces/default/images/gsdlhead.gif"><xsl:attribute name="alt"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'gsdl')"/></xsl:attribute>
+            </img>
+	  </div>
+      </div>
+      <div class="bannerextra"></div>
+      <div id="content">
+        <xsl:call-template name="dividerBar">
+            <xsl:with-param name="text" select="'select a collection'"/> 
+        </xsl:call-template>
+      </div>			
+   </xsl:template>
+
+  <xsl:template name="genericPageBanner">
+    <xsl:param name='text'/>
+    <xsl:variable name="lang" select="/page/@lang"/>
+    <center>
+      <table width="100%">
+	<tr><td align="left"></td>
+	  <td align="right">
+	    <table>
+	      <tr><td class="gsbutton">
+		  <a class="gsbutton" href="{$library_name}?a=p&amp;sa=home">
+		    <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'home_b')"/>
+		  </a>
+		</td></tr></table>
+	  </td>
+	</tr>
+      </table>
+    </center>
+    <xsl:call-template name="dividerBar"><xsl:with-param name='text' select="$text"/></xsl:call-template>
+  </xsl:template>
+  
+  <xsl:template name="standardPageBanner">
+    <xsl:param name="collName"/>
+    <xsl:param name="pageType"/>
+    <xsl:param name="clTop"/>
+    <xsl:variable name="this-element" select="/page/pageResponse/collection"/>
+     <div id="bannar">
+      <div class="pageinfo"> 
+          <xsl:call-template name="top-buttons">
+	    <xsl:with-param name="collName" select="$collName"/>
+	    <xsl:with-param name="pageType" select="$pageType"/>
+	  </xsl:call-template>
+          <xsl:if test="not(/page/pageRequest/@action='d')">
+  	<xsl:variable name="text">
+	  <xsl:choose>
+	    <xsl:when test="$pageType='browse'">
+	      <xsl:value-of select="/page/pageResponse/collection/serviceList/service[@name='ClassifierBrowse']/classifierList/classifier[@name=$clTop]/displayItem[@name='name']"/>
+	    </xsl:when>
+	    <xsl:otherwise>
+	      <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, concat($pageType, '_t'))"/>
+	    </xsl:otherwise>
+	  </xsl:choose>
+	</xsl:variable>
+        <p class="bannertitle"><xsl:value-of select="$text"/></p>	 
+      </xsl:if>
+     </div>
+
+     <div class="collectimage">
+       <a href="{$library_name}?a=p&amp;sa=about&amp;c={$collName}">
+	    <xsl:choose>
+	      <xsl:when test="$this-element/displayItem[@name='icon']">
+		<img border="0">
+		  <xsl:attribute name="src">
+		    <xsl:value-of select="$this-element/metadataList/metadata[@name='httpPath']"/>/images/<xsl:value-of select="$this-element/displayItem[@name='icon']"/>
+		  </xsl:attribute>	
+		  <xsl:attribute name="alt">
+		    <xsl:value-of select="$this-element/displayItem[@name='name']"/>
+		  </xsl:attribute>
+		  <xsl:attribute name="title">
+		    <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'aboutpage')"/>
+		  </xsl:attribute>
+		</img>
+	      </xsl:when>
+	      <xsl:otherwise>
+		<b><xsl:value-of select="$this-element/displayItem[@name='name']"/>hello</b>
+	      </xsl:otherwise>
+	    </xsl:choose>
+	  </a>
+       </div>
+      </div>
+    <div class="bannerextra"></div>	
+  </xsl:template>
+  
+  <xsl:template name="top-buttons">
+    <xsl:param name="collName"/>
+    <xsl:param name="pageType"/>
+    <p class="bannerlinks">
+      	  <a class="navlink" href="{$library_name}?a=p&amp;sa=home"><xsl:attribute name="title"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'home_tip')"/></xsl:attribute>
+	    <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'home_b')"/>
+	  </a>
+	<!-- <xsl:choose>
+	<xsl:when test="$pageType='help'">
+             <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'help_b')"/>
+        </xsl:when>
+	<xsl:otherwise>
+	  <a class="navlink" href="{$library_name}?a=p&amp;sa=help&amp;c={$collName}"><xsl:attribute name="title"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'help_tip')"/></xsl:attribute>
+	<xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'help_b')"/>
+          </a>
+       </xsl:otherwise>
+      </xsl:choose> -->
+       <xsl:choose>
+	  <xsl:when test="$pageType='pref'">
+	      <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref_b')"/>
+	   </xsl:when>
+	  <xsl:otherwise>
+	    <a class="navlink" href="{$library_name}?a=p&amp;sa=pref&amp;c={$collName}"><xsl:attribute name="title"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref_tip')"/></xsl:attribute>
+		<xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref_b')"/>
+	    </a>
+	   </xsl:otherwise>
+	</xsl:choose>      
+    </p>
+  </xsl:template>
+  
+  <xsl:template name="navigationBar">
+    <xsl:param name="collName"/>
+    <xsl:param name="clTop"/>
+    <xsl:variable name="this-element" select="/page/pageResponse/collection"/>
+    <xsl:variable name="this-service" select="/page/pageResponse/service/@name"/>
+    <xsl:variable name="classifiers" select="$this-element/serviceList/service[@name='ClassifierBrowse']/classifierList"/>
+     <div class="navbar">
+       <p class="navbar">
+	 <xsl:if test="$this-element/serviceList/service[@type='query']">
+	   <xsl:call-template name="navbar-search"><xsl:with-param name="collName" select="$collName"/></xsl:call-template>
+	 </xsl:if>
+	
+	<xsl:for-each select="$classifiers/classifier">
+	  <xsl:apply-templates select="." mode="navbar">
+	    <xsl:with-param name="collName" select="$collName"/>
+	    <xsl:with-param name="clTop" select="$clTop"/>
+	  </xsl:apply-templates>
+	</xsl:for-each>
+	
+	<xsl:if test="$this-element/serviceList/service[@name='PhindApplet']">
+	  <xsl:call-template name="navbar-phind"><xsl:with-param name="collName" select="$collName"/></xsl:call-template>
+	</xsl:if>
+       </p>
+      </div> 
+  </xsl:template>
+
+  <xsl:template name="navbar-search">
+    <xsl:param name="collName"/>
+    <xsl:choose>
+      <xsl:when test="/page/pageRequest/@action='q'">	  
+	   <span class="narspace">search</span>
+      </xsl:when>
+      <xsl:otherwise>
+	<xsl:variable name="service">
+	  <xsl:choose>
+	    <xsl:when  test="not(/page/pageRequest/paramList/param[@name='ct'])">TextQuery</xsl:when>
+	    <xsl:when test="/page/pageRequest/paramList/param[@name='ct']/@value='0'">TextQuery</xsl:when>
+	    <xsl:when test="/page/pageRequest/paramList/param[@name='qt']/@value='1'"><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name='qfm']/@value='1'">AdvancedFieldQuery</xsl:when><xsl:otherwise>FieldQuery</xsl:otherwise></xsl:choose></xsl:when>
+	    <xsl:otherwise>TextQuery</xsl:otherwise>
+	  </xsl:choose>
+	</xsl:variable>
+	<a class="navlink" href="{$library_name}?a=q&amp;rt=d&amp;s={$service}&amp;c={$collName}"><xsl:attribute name='title'><xsl:value-of select="/page/pageResponse/collection/service[@name=$service]/displayItem[@name='description']"/></xsl:attribute>search</a>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+  
+  <xsl:template name="navbar-phind">
+    <xsl:param name="collName"/>
+    <xsl:choose>
+      <xsl:when test="/page/pageRequest/paramList/param[@name='s']/@value='PhindApplet'">
+	    <span class="narspace">phrases</span>
+      </xsl:when>
+      <xsl:otherwise>
+	 <a class="navlink" href="{$library_name}?a=a&amp;rt=d&amp;s=PhindApplet&amp;c={$collName}"><xsl:if test="/page/pageResponse/collection/service[@name='PhindApplet']/displayItem[@name='description']"><xsl:attribute name='title'><xsl:value-of select="/page/pageResponse/collection/service[@name='PhindApplet']/displayItem[@name='description']"/></xsl:attribute></xsl:if>phrases</a>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="classifier" mode="navbar">
+    <xsl:param name="collName"/>
+    <xsl:param name="clTop"/>
+    <xsl:choose>
+      <xsl:when test="/page/pageRequest/@action='b' and $clTop=@name">
+	 <span class="narspace"><xsl:value-of select="displayItem[@name='name']"/></span>
+      </xsl:when>
+      <xsl:otherwise>
+	<a class="navlink" href="{$library_name}?a=b&amp;rt=r&amp;s=ClassifierBrowse&amp;c={$collName}&amp;cl={@name}"><xsl:attribute name='title'><xsl:value-of select="displayItem[@name='description']"/></xsl:attribute><xsl:value-of select="displayItem[@name='name']"/></a>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template name="dividerBar">   
+    <xsl:param name='text'/>
+      <xsl:choose>
+      <xsl:when test="$text">
+	 <div class="divbar"><p class="navbar"><xsl:value-of select="$text"/></p></div>
+      </xsl:when>
+      <xsl:otherwise>
+	 <div class="divbar"><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text></div>
+      </xsl:otherwise>
+    </xsl:choose> 
+  </xsl:template>
+  
+  <xsl:template name="nzdlPageBanner">
+       <div><img src="interfaces/nzdl/images/nzdl2gr.gif" width="457" height="181" ><xsl:attribute name="alt"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'nzdl')"/></xsl:attribute></img></div>
+       <!-- end of page banner -->  
+  </xsl:template>
+
+  <xsl:template name="greenstoneFooter">
+    <div class="divbar"><p class="navbar">powered by greenstone3</p>
+    </div>
+  </xsl:template>
+  
+  <xsl:template name="imagegreenstone">
+    <img src="interfaces/nzdl/images/gsdl.gif" width="140" height="77" border="0" hspace='0'><xsl:attribute name='alt'><xsl:call-template name='textimagegreenstone'/></xsl:attribute></img>
+  </xsl:template>
+  
+  <!-- Display the appropriate image, depending on the node type -->
+  <xsl:template match="documentNode" mode="displayNodeIcon">
+    
+    <!-- Root node: book icon (open or closed) -->
+    <xsl:choose>
+      <xsl:when test="@nodeType='root'">
+	<xsl:choose>
+	  <xsl:when test="documentNode">
+	    <xsl:call-template name="openbookimg">
+	      <xsl:with-param name="title">Close this book</xsl:with-param>
+	    </xsl:call-template>
+	  </xsl:when>
+	  <xsl:otherwise>
+	    <xsl:call-template name="closedbookimg">
+	      <xsl:with-param name="title">Open this document and view contents</xsl:with-param>
+	    </xsl:call-template>
+	  </xsl:otherwise>
+	</xsl:choose>
+      </xsl:when>
+      
+      <!-- Internal node: folder icon (open or closed) -->
+      <xsl:when test="@nodeType='internal'">
+	<xsl:choose>
+	  <xsl:when test="documentNode">
+	    <xsl:call-template name="openfolderimg">
+	      <xsl:with-param name="title">Close this folder</xsl:with-param>
+	    </xsl:call-template>
+	  </xsl:when>
+	  <xsl:otherwise>
+	    <xsl:call-template name="closedfolderimg">
+	      <xsl:with-param name="title">Open this folder and view contents</xsl:with-param>
+	    </xsl:call-template>
+	  </xsl:otherwise>
+	</xsl:choose>
+      </xsl:when>
+      
+      <!-- Leaf node: page icon, and this is the default -->
+      <xsl:otherwise>
+	<xsl:call-template name="textpageimg">
+	  <xsl:with-param name="title">View the document</xsl:with-param>
+	</xsl:call-template>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+
+  <xsl:template name="openbookimg">
+    <xsl:param name="alt"/>
+    <xsl:param name="title"/>
+    <img border="0" width="28" height="23" 
+      src="interfaces/default/images/openbook.gif"
+      alt="{$alt}" title="{$title}"/>
+  </xsl:template>
+
+  <xsl:template name="closedbookimg">
+    <xsl:param name="alt"/>
+    <xsl:param name="title"/>
+    <img border="0" width="18" height="11"  
+      src="interfaces/default/images/book.gif"
+      alt="{$alt}" title="{$title}"/>
+  </xsl:template>
+
+  <xsl:template name="openfolderimg">
+    <xsl:param name="alt"/>
+    <xsl:param name="title"/>
+    <img border="0" width="23" height="15"  
+      src="interfaces/default/images/openfldr.gif"
+      alt="{$alt}" title="{$title}"/>
+  </xsl:template>
+
+  <xsl:template name="closedfolderimg">
+    <xsl:param name="alt"/>
+    <xsl:param name="title"/>
+    <img border="0" width="23" height="15" 
+      src="interfaces/default/images/clsdfldr.gif"
+      alt="{$alt}" title="{$title}"/>
+  </xsl:template>
+
+  <xsl:template name="textpageimg">
+    <xsl:param name="alt"/>
+    <xsl:param name="title"/>
+    <img border="0" width="16" height="21"
+      src="interfaces/default/images/itext.gif"
+      alt="{$alt}" title="{$title}"/>
+  </xsl:template>
+
+  <xsl:template name="bookshelfimg">
+    <xsl:param name="alt"/>
+    <xsl:param name="title"/>
+    <img border="0" width="20" height="16" 
+      src="interfaces/default/images/bshelf.gif"  
+      alt="{$alt}" title="{$title}"/>
+  </xsl:template>
+
+  <xsl:template name="iconpdf">
+    <xsl:param name="alt">PDF</xsl:param>
+    <xsl:param name="title"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'texticonpdf')"/></xsl:param>
+    <img border="0" width='26' height='26' 
+      src='interfaces/default/images/ipdf.gif' 
+      alt='{$alt}' title='{$title}'/>
+  </xsl:template>
+    
+  <xsl:template name="icondoc">
+    <xsl:param name="alt">Word</xsl:param>
+    <xsl:param name="title"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'texticonmsword')"/></xsl:param>
+    <img border="0" width='26' height='26' 
+      src='interfaces/default/images/imsword.gif' 
+      alt='{$alt}' title='{$title}'/>
+  </xsl:template>
+
+</xsl:stylesheet>  
Index: /greenstone3/trunk/web/interfaces/default/interfaceConfig.xml
===================================================================
--- /greenstone3/trunk/web/interfaces/default/interfaceConfig.xml	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/interfaceConfig.xml	(revision 14125)
@@ -0,0 +1,43 @@
+<interfaceConfig>
+  <actionList>
+    <action name='p' class='PageAction'>
+      <subaction name='home' xslt='home.xsl'/>
+      <subaction name='about' xslt='about.xsl'/>
+      <subaction name='help' xslt='help.xsl'/>
+      <subaction name='pref' xslt='pref.xsl'/>
+      <subaction name='nav' xslt='nav.xsl'/><!-- used for the collection header frame -->
+      <subaction name="html" xslt="html.xsl"/> <!-- use to put an external page into a frame with a collection header-->
+    </action>
+    <action name='q' class='QueryAction' xslt='query.xsl'/>
+    <action name='b' class='GS2BrowseAction' xslt='classifier.xsl'/>
+    <action name='a' class='AppletAction' xslt='applet.xsl'/>
+    <action name='d' class='DocumentAction' xslt='document.xsl'/>
+    <action name='xd' class='XMLDocumentAction'>
+      <subaction name='toc' xslt='document-toc.xsl'/>
+      <subaction name='text' xslt='document-content.xsl'/>
+    </action>
+    <action name='pr' class='ProcessAction' xslt='process.xsl'/>
+    <action name='s' class='SystemAction' xslt='system.xsl'/>
+    <action name='g' class='GeneralAction'>
+      <subaction name="berry" xslt='berry.xsl'/>
+    </action>
+  </actionList>
+  <languageList>
+    <language name="en">
+      <displayItem name='name'>English</displayItem>
+    </language>
+    <language name="fr">
+      <displayItem name='name'>FranÃ§ais</displayItem>
+    </language>
+    <language name='es'>
+      <displayItem name='name'>EspaÃ±ol</displayItem>
+    </language>
+    <language name="jp">
+      <displayItem name='name'>ã«ã»ãã</displayItem>
+    </language>
+  </languageList>
+  <optionList>
+    <option name="highlightQueryTerms" value="true"/>
+    <option name="berryBaskets" value="true"/>
+  </optionList>
+</interfaceConfig>
Index: /greenstone3/trunk/web/interfaces/default/js/YAHOO.js
===================================================================
--- /greenstone3/trunk/web/interfaces/default/js/YAHOO.js	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/js/YAHOO.js	(revision 14125)
@@ -0,0 +1,63 @@
+/*
+Copyright (c) 2006 Yahoo! Inc. All rights reserved.
+version 0.9.0
+*/
+
+/**
+ * @class The Yahoo global namespace
+ */
+var YAHOO = function() {
+
+    return {
+
+        /**
+         * Yahoo presentation platform utils namespace
+         */
+        util: {},
+
+        /**
+         * Yahoo presentation platform widgets namespace
+         */
+        widget: {},
+
+        /**
+         * Yahoo presentation platform examples namespace
+         */
+        example: {},
+
+        /**
+         * Returns the namespace specified and creates it if it doesn't exist
+         *
+         * YAHOO.namespace("property.package");
+         * YAHOO.namespace("YAHOO.property.package");
+         *
+         * Either of the above would create YAHOO.property, then
+         * YAHOO.property.package
+         *
+         * @param  {String} sNameSpace String representation of the desired
+         *                             namespace
+         * @return {Object}            A reference to the namespace object
+         */
+        namespace: function( sNameSpace ) {
+
+            if (!sNameSpace || !sNameSpace.length) {
+                return null;
+            }
+
+            var levels = sNameSpace.split(".");
+
+            var currentNS = YAHOO;
+
+            // YAHOO is implied, so it is ignored if it is included
+            for (var i=(levels[0] == "YAHOO") ? 1 : 0; i<levels.length; ++i) {
+                currentNS[levels[i]] = currentNS[levels[i]] || {};
+                currentNS = currentNS[levels[i]];
+            }
+
+            return currentNS;
+
+        }
+    };
+
+} ();
+
Index: /greenstone3/trunk/web/interfaces/default/js/connection.js
===================================================================
--- /greenstone3/trunk/web/interfaces/default/js/connection.js	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/js/connection.js	(revision 14125)
@@ -0,0 +1,465 @@
+/*
+Copyright (c) 2006 Yahoo! Inc. All rights reserved.
+version 0.9.0
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response returning the results to a pre-defined
+ * callback function you create.
+ * @ class
+ */
+YAHOO.util.Connect = {};
+
+YAHOO.util.Connect =
+{
+  /**
+   * Array of  MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.5.0',
+		'MSXML2.XMLHTTP.4.0',
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Array of HTTP header(s)
+   * @private
+   * @type array
+   */
+	_http_header:[],
+
+ /**
+  * Property modified by setForm() to determine if the transaction
+  * should be processed as a HTML form POST.
+  * @private
+  * @type boolean
+  */
+	_isFormPost:false,
+
+ /**
+  * Property modified by setForm() to the HTML form POST body.
+  * @private
+  * @type string
+  */
+	_sFormData:null,
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR  readyState.
+   * The default is 300 milliseconds.
+   * @private
+   * @type int
+   */
+	_polling_interval:300,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+	_transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this.msxml_progid.unshift(id);
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   * @type object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and id properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and id properties
+					obj = { conn:http, tId:transactionId };
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest and syncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param callbackArg User-defined callback arguments
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var errorObj;
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			var oConn = this;
+
+			o.conn.open(method, uri, true);
+		    this.handleReadyState(o, callback);
+
+			if(this._isFormPost){
+				postData = this._sFormData;
+				this._isFormPost = false;
+			}
+			else if(postData){
+				this.initHeader('Content-Type','application/x-www-form-urlencoded');
+			}
+
+			//Verify whether the transaction has any user-defined HTTP headers
+			//and set them.
+			if(this._http_header.length>0){
+				this.setHeader(o);
+			}
+			postData?o.conn.send(postData):o.conn.send(null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @param callbackArg User-defined arguments passed to the callback
+   * @return void
+   */
+	handleReadyState:function(o, callback)
+	{
+		var oConn = this;
+		var poll = window.setInterval(
+			function(){
+				if(o.conn.readyState==4){
+					oConn.handleTransactionResponse(o, callback);
+					window.clearInterval(poll);
+				}
+			}
+		,this._polling_interval);
+	},
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {function} callback - User-defined callback object
+   * @param {} callbackArg - User-defined arguments to be passed to the callback
+   * @return void
+   */
+	handleTransactionResponse:function(o, callback)
+	{
+		var httpStatus;
+		var responseObject;
+
+		try{
+			httpStatus = o.conn.status;
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus == 200){
+			responseObject = this.createResponseObject(o, callback.argument);
+			if(callback.success){
+				if(!callback.scope){
+					callback.success(responseObject);
+				}
+				else{
+					callback.success.apply(callback.scope, [responseObject]);
+				}
+			}
+		}
+		else{
+			switch(httpStatus){
+				// The following case labels are wininet.dll error codes that may be encountered.
+				// Server timeout
+				case 12002:
+				// 12029 to 12031 correspond to dropped connections.
+				case 12029:
+				case 12030:
+				case 12031:
+				// Connection closed by server.
+				case 12152:
+				// See above comments for variable status.
+				case 13030:
+					responseObject = this.createExceptionObject(o, callback.argument);
+					if(callback.failure){
+						if(!callback.scope){
+							callback.failure(responseObject);
+						}
+						else{
+							callback.failure.apply(callback.scope,[responseObject]);
+						}
+					}
+					break;
+				default:
+					responseObject = this.createResponseObject(o, callback.argument);
+					if(callback.failure){
+						if(!callback.scope){
+							callback.failure(responseObject);
+						}
+						else{
+							callback.failure.apply(callback.scope,[responseObject]);
+						}
+					}
+			}
+		}
+
+		this.releaseObject(o);
+	},
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases(and exceptions) will differ in their defined properties
+   * but property "type" will confirm the transaction's status.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined arguments to be passed to the callback
+   * @param {boolean} isSuccess Indicates whether the transaction was successful or not.
+   * @return object
+   */
+	createResponseObject:function(o, callbackArg)
+	{
+		var obj = {};
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.allResponseHeaders = o.conn.getAllResponseHeaders();
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+	},
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The object's property "type" value will be "failure", and two additional
+   * unique, properties are added - errorCode and errorText.
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param {string} errorCode Error code associated with the exception.
+   * @param {string} errorText Error message describing the exception.
+   * @return object
+   */
+	createExceptionObject:function(tId, callbackArg)
+	{
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+
+		var obj = {};
+
+		obj.tId = tId;
+		obj.status = COMM_CODE;
+		obj.statusText = COMM_ERROR;
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+	},
+
+  /**
+   * Accessor that stores the HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		var oHeader = [label,value];
+		this._http_header.push(oHeader);
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		var oHeader = this._http_header;
+		for(var i=0;i<oHeader.length;i++){
+			o.conn.setRequestHeader(oHeader[i][0],oHeader[i][1]);
+		}
+		oHeader.splice(0,oHeader.length);
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded POST body.  Both syncRequest()
+   * and asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string} formName value of form name attribute
+   * @return void
+   */
+	setForm:function(formName)
+	{
+		this._sFormData = '';
+		var oForm = document.forms[formName];
+		var oElement, elName, elValue;
+		// iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			elName = oForm.elements[i].name;
+			elValue = oForm.elements[i].value;
+			switch (oElement.type)
+			{
+				case 'select-multiple':
+					for(var j=0; j<oElement.options.length; j++){
+						if(oElement.options[j].selected){
+							this._sFormData += encodeURIComponent(elName) + '=' + encodeURIComponent(oElement.options[j].value) + '&';
+						}
+					}
+					break;
+				case 'radio':
+				case 'checkbox':
+					if(oElement.checked){
+						this._sFormData += encodeURIComponent(elName) + '=' + encodeURIComponent(elValue) + '&';
+					}
+					break;
+				case 'file':
+				// stub case as XMLHttpRequest will only send the file path as a string.
+					break;
+				case undefined:
+				// stub case for fieldset element which returns undefined.
+					break;
+				default:
+					this._sFormData += encodeURIComponent(elName) + '=' + encodeURIComponent(elValue) + '&';
+					break;
+			}
+		}
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		this._isFormPost = true;
+		this.initHeader('Content-Type','application/x-www-form-urlencoded');
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @return void
+   */
+	abort:function(o)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			this.releaseObject(o);
+		}
+	},
+
+  /**
+   * Accessor to check if the transaction associated with the connection object
+   * is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		if(o){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+			//dereference the XHR instance.
+			o.conn = null;
+			//dereference the connection object.
+			o = null;
+	}
+}
Index: /greenstone3/trunk/web/interfaces/default/js/dom.js
===================================================================
--- /greenstone3/trunk/web/interfaces/default/js/dom.js	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/js/dom.js	(revision 14125)
@@ -0,0 +1,433 @@
+/*
+Copyright (c) 2006 Yahoo! Inc. All rights reserved.
+version 0.9.0
+*/
+
+/**
+ * @class Provides helper methods for DOM elements.
+ */
+YAHOO.util.Dom = new function() {
+
+   /**
+    * Returns an HTMLElement reference
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    * @return {HTMLElement} A DOM reference to an HTML element.
+    */
+   this.get = function(el) {
+      if (typeof el == 'string') { // accept object or id
+         el = document.getElementById(el);
+      }
+
+      return el;
+   };
+
+   /**
+    * Normalizes currentStyle and ComputedStyle.
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    * @param {String} property The style property whose value is returned.
+    * @return {String} The current value of the style property.
+    */
+   this.getStyle = function(el, property) {
+      var value = null;
+      var dv = document.defaultView;
+
+      el = this.get(el);
+
+      if (property == 'opacity' && el.filters) {// IE opacity
+         value = 1;
+         try {
+            value = el.filters.item('DXImageTransform.Microsoft.Alpha').opacity / 100;
+         } catch(e) {
+            try {
+               value = el.filters.item('alpha').opacity / 100;
+            } catch(e) {}
+         }
+      }
+      else if (el.style[property]) {
+         value = el.style[property];
+      }
+      else if (el.currentStyle && el.currentStyle[property]) {
+         value = el.currentStyle[property];
+      }
+      else if ( dv && dv.getComputedStyle )
+      {  // convert camelCase to hyphen-case
+
+         var converted = '';
+         for(i = 0, len = property.length;i < len; ++i) {
+            if (property.charAt(i) == property.charAt(i).toUpperCase()) {
+               converted = converted + '-' + property.charAt(i).toLowerCase();
+            } else {
+               converted = converted + property.charAt(i);
+            }
+         }
+
+         if (dv.getComputedStyle(el, '').getPropertyValue(converted)) {
+            value = dv.getComputedStyle(el, '').getPropertyValue(converted);
+         }
+      }
+
+      return value;
+   };
+
+   /**
+    * Wrapper for setting style properties of HTMLElements.  Normalizes "opacity" across modern browsers.
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    * @param {String} property The style property to be set.
+    * @param {String} val The value to apply to the given property.
+    */
+   this.setStyle = function(el, property, val) {
+      el = this.get(el);
+      switch(property) {
+         case 'opacity' :
+            if (el.filters) {
+               el.style.filter = 'alpha(opacity=' + val * 100 + ')';
+
+               if (!el.currentStyle.hasLayout) {
+                  el.style.zoom = 1;
+               }
+            } else {
+               el.style.opacity = val;
+               el.style['-moz-opacity'] = val;
+               el.style['-khtml-opacity'] = val;
+            }
+            break;
+         default :
+            el.style[property] = val;
+      }
+   };
+
+   /**
+    * Gets the current position of an element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    */
+   this.getXY = function(el) {
+      el = this.get(el);
+
+      // has to be part of document to have pageXY
+      if (el.parentNode === null || this.getStyle(el, 'display') == 'none') {
+         return false;
+      }
+
+      /**
+       * Position of the html element (x, y)
+       * @private
+       * @type Array
+       */
+      var parent = null;
+      var pos = [];
+      var box;
+
+      if (el.getBoundingClientRect) { // IE
+         box = el.getBoundingClientRect();
+         var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
+         var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
+
+         return [box.left + scrollLeft, box.top + scrollTop];
+      }
+      else if (document.getBoxObjectFor) { // gecko
+         box = document.getBoxObjectFor(el);
+         pos = [box.x, box.y];
+      }
+      else { // safari/opera
+         pos = [el.offsetLeft, el.offsetTop];
+         parent = el.offsetParent;
+         if (parent != el) {
+            while (parent) {
+               pos[0] += parent.offsetLeft;
+               pos[1] += parent.offsetTop;
+               parent = parent.offsetParent;
+            }
+         }
+
+         // opera & (safari absolute) incorrectly account for body offsetTop
+         var ua = navigator.userAgent.toLowerCase();
+         if (
+            ua.indexOf('opera') != -1
+            || ( ua.indexOf('safari') != -1 && this.getStyle(el, 'position') == 'absolute' )
+         ) {
+            pos[1] -= document.body.offsetTop;
+         }
+      }
+
+      if (el.parentNode) { parent = el.parentNode; }
+      else { parent = null; }
+
+      while (parent && parent.tagName != 'BODY' && parent.tagName != 'HTML') {
+         pos[0] -= parent.scrollLeft;
+         pos[1] -= parent.scrollTop;
+
+         if (parent.parentNode) { parent = parent.parentNode; }
+         else { parent = null; }
+      }
+
+      return pos;
+   };
+
+   /**
+    * Gets the current X position of an element based on page coordinates.  The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    */
+   this.getX = function(el) {
+      return this.getXY(el)[0];
+   };
+
+   /**
+    * Gets the current Y position of an element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    */
+   this.getY = function(el) {
+      return this.getXY(el)[1];
+   };
+
+   /**
+    * Set the position of an html element in page coordinates, regardless of how the element is positioned.
+    * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    * @param {array} pos Contains X & Y values for new position (coordinates are page-based)
+    */
+   this.setXY = function(el, pos, noRetry) {
+      el = this.get(el);
+      var pageXY = YAHOO.util.Dom.getXY(el);
+      if (pageXY === false) { return false; } // has to be part of doc to have pageXY
+
+      if (this.getStyle(el, 'position') == 'static') { // default to relative
+         this.setStyle(el, 'position', 'relative');
+      }
+
+      var delta = [
+         parseInt( YAHOO.util.Dom.getStyle(el, 'left'), 10 ),
+         parseInt( YAHOO.util.Dom.getStyle(el, 'top'), 10 )
+      ];
+
+      if ( isNaN(delta[0]) ) { delta[0] = 0; } // defalts to 'auto'
+      if ( isNaN(delta[1]) ) { delta[1] = 0; }
+
+      if (pos[0] !== null) { el.style.left = pos[0] - pageXY[0] + delta[0] + 'px'; }
+      if (pos[1] !== null) { el.style.top = pos[1] - pageXY[1] + delta[1] + 'px'; }
+
+      var newXY = this.getXY(el);
+
+      // if retry is true, try one more time if we miss
+      if (!noRetry && (newXY[0] != pos[0] || newXY[1] != pos[1]) ) {
+         this.setXY(el, pos, true);
+      }
+
+      return true;
+   };
+
+   /**
+    * Set the X position of an html element in page coordinates, regardless of how the element is positioned.
+    * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    * @param {Int} x to use as the X coordinate.
+    */
+   this.setX = function(el, x) {
+      return this.setXY(el, [x, null]);
+   };
+
+   /**
+    * Set the Y position of an html element in page coordinates, regardless of how the element is positioned.
+    * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    * @param {Int} Value to use as the Y coordinate.
+    */
+   this.setY = function(el, y) {
+      return this.setXY(el, [null, y]);
+   };
+
+   /**
+    * Returns the region position of the given element.
+    * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    * @return {Region} A Region instance containing "top, left, bottom, right" member data.
+    */
+   this.getRegion = function(el) {
+      el = this.get(el);
+      return new YAHOO.util.Region.getRegion(el);
+   };
+
+   /**
+    * Returns the width of the client (viewport).
+    * @return {Int} The width of the viewable area of the page.
+    */
+   this.getClientWidth = function() {
+      return (
+         document.documentElement.offsetWidth
+         || document.body.offsetWidth
+      );
+   };
+
+   /**
+    * Returns the height of the client (viewport).
+    * @return {Int} The height of the viewable area of the page.
+    */
+   this.getClientHeight = function() {
+      return (
+         self.innerHeight
+         || document.documentElement.clientHeight
+         || document.body.clientHeight
+      );
+   };
+};
+
+/**
+ * @class A region is a representation of an object on a grid.  It is defined
+ * by the top, right, bottom, left extents, so is rectangular by default.  If
+ * other shapes are required, this class could be extended to support it.
+ *
+ * @param {int} t the top extent
+ * @param {int} r the right extent
+ * @param {int} b the bottom extent
+ * @param {int} l the left extent
+ * @constructor
+ */
+YAHOO.util.Region = function(t, r, b, l) {
+
+    /**
+     * The region's top extent
+     * @type int
+     */
+    this.top = t;
+
+    /**
+     * The region's right extent
+     * @type int
+     */
+    this.right = r;
+
+    /**
+     * The region's bottom extent
+     * @type int
+     */
+    this.bottom = b;
+
+    /**
+     * The region's left extent
+     * @type int
+     */
+    this.left = l;
+};
+
+/**
+ * Returns true if this region contains the region passed in
+ *
+ * @param  {Region}  region The region to evaluate
+ * @return {boolean}        True if the region is contained with this region,
+ *                          else false
+ */
+YAHOO.util.Region.prototype.contains = function(region) {
+    return ( region.left   >= this.left   &&
+             region.right  <= this.right  &&
+             region.top    >= this.top    &&
+             region.bottom <= this.bottom    );
+};
+
+/**
+ * Returns the area of the region
+ *
+ * @return {int} the region's area
+ */
+YAHOO.util.Region.prototype.getArea = function() {
+    return ( (this.bottom - this.top) * (this.right - this.left) );
+};
+
+/**
+ * Returns the region where the passed in region overlaps with this one
+ *
+ * @param  {Region} region The region that intersects
+ * @return {Region}        The overlap region, or null if there is no overlap
+ */
+YAHOO.util.Region.prototype.intersect = function(region) {
+    var t = Math.max( this.top,    region.top    );
+    var r = Math.min( this.right,  region.right  );
+    var b = Math.min( this.bottom, region.bottom );
+    var l = Math.max( this.left,   region.left   );
+
+    if (b >= t && r >= l) {
+        return new YAHOO.util.Region(t, r, b, l);
+    } else {
+        return null;
+    }
+};
+
+/**
+ * Returns the region representing the smallest region that can contain both
+ * the passed in region and this region.
+ *
+ * @param  {Region} region The region that to create the union with
+ * @return {Region}        The union region
+ */
+YAHOO.util.Region.prototype.union = function(region) {
+    var t = Math.min( this.top,    region.top    );
+    var r = Math.max( this.right,  region.right  );
+    var b = Math.max( this.bottom, region.bottom );
+    var l = Math.min( this.left,   region.left   );
+
+    return new YAHOO.util.Region(t, r, b, l);
+};
+
+/**
+ * toString
+ * @return string the region properties
+ */
+YAHOO.util.Region.prototype.toString = function() {
+    return ( "Region {" +
+             "  t: "    + this.top    +
+             ", r: "    + this.right  +
+             ", b: "    + this.bottom +
+             ", l: "    + this.left   +
+             "}" );
+}
+
+/**
+ * Returns a region that is occupied by the DOM element
+ *
+ * @param  {HTMLElement} el The element
+ * @return {Region}         The region that the element occupies
+ * @static
+ */
+YAHOO.util.Region.getRegion = function(el) {
+    var p = YAHOO.util.Dom.getXY(el);
+
+    var t = p[1];
+    var r = p[0] + el.offsetWidth;
+    var b = p[1] + el.offsetHeight;
+    var l = p[0];
+
+    return new YAHOO.util.Region(t, r, b, l);
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * @class
+ *
+ * A point is a region that is special in that it represents a single point on
+ * the grid.
+ *
+ * @param {int} x The X position of the point
+ * @param {int} y The Y position of the point
+ * @constructor
+ * @extends Region
+ */
+YAHOO.util.Point = function(x, y) {
+    /**
+     * The X position of the point
+     * @type int
+     */
+    this.x      = x;
+
+    /**
+     * The Y position of the point
+     * @type int
+     */
+    this.y      = y;
+
+    this.top    = y;
+    this.right  = x;
+    this.bottom = y;
+    this.left   = x;
+};
+
+YAHOO.util.Point.prototype = new YAHOO.util.Region();
Index: /greenstone3/trunk/web/interfaces/default/js/dragdrop-debug.js
===================================================================
--- /greenstone3/trunk/web/interfaces/default/js/dragdrop-debug.js	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/js/dragdrop-debug.js	(revision 14125)
@@ -0,0 +1,2517 @@
+/*
+Copyright (c) 2006 Yahoo! Inc. All rights reserved.
+version 0.9.0
+*/
+
+/**
+ * @class Defines the interface and base operation of items that that can be
+ * dragged or can be drop targets.  It was designed to be extended, overriding
+ * the event handlers for startDrag, onDrag, onDragOver, onDragOut.
+ * Up to three html elements can be associated with a DragDrop instance:
+ * <ul>
+ * <li>linked element: the element that is passed into the constructor.
+ * This is the element which defines the boundaries for interaction with
+ * other DragDrop objects.</li>
+ * <li>handle element(s): The drag operation only occurs if the element that
+ * was clicked matches a handle element.  By default this is the linked
+ * element, but there are times that you will want only a portion of the
+ * linked element to initiate the drag operation, and the setHandleElId()
+ * method provides a way to define this.</li>
+ * <li>drag element: this represents an the element that would be moved along
+ * with the cursor during a drag operation.  By default, this is the linked
+ * element itself as in {@link YAHOO.util.DD}.  setDragElId() lets you define
+ * a separate element that would be moved, as in {@link YAHOO.util.DDProxy}
+ * </li>
+ * </ul>
+ * This class should not be instantiated until the onload event to ensure that
+ * the associated elements are available.
+ * The following would define a DragDrop obj that would interact with any
+ * other * DragDrop obj in the "group1" group:
+ * <pre>
+ *  dd = new YAHOO.util.DragDrop("div1", "group1");
+ * </pre>
+ * Since none of the event handlers have been implemented, nothing would
+ * actually happen if you were to run the code above.  Normally you would
+ * override this class or one of the default implementations, but you can
+ * also override the methods you want on an instance of the class...
+ * <pre>
+ *  dd.onDragDrop = function(e, id) {
+ *   alert("dd was dropped on " + id);
+ *  }
+ * </pre>
+ * @constructor
+ * @param {String} id of the element that is linked to this instance
+ * @param {String} sGroup the group of related DragDrop objects
+ */
+YAHOO.util.DragDrop = function(id, sGroup) {
+    if (id) {
+        this.init(id, sGroup);
+    }
+};
+
+YAHOO.util.DragDrop.prototype = {
+
+    /**
+     * The id of the element associated with this object.  This is what we
+     * refer to as the "linked element" because the size and position of
+     * this element is used to determine when the drag and drop objects have
+     * interacted.
+     *
+     * @type String
+     */
+    id: null,
+
+    /**
+     * The id of the element that will be dragged.  By default this is same
+     * as the linked element , but could be changed to another element. Ex:
+     * YAHOO.util.DDProxy
+     *
+     * @type String
+     * @private
+     */
+    dragElId: null,
+
+    /**
+     * the id of the element that initiates the drag operation.  By default
+     * this is the linked element, but could be changed to be a child of this
+     * element.  This lets us do things like only starting the drag when the
+     * header element within the linked html element is clicked.
+     *
+     * @type String
+     * @private
+     */
+    handleElId: null,
+
+    /**
+     * An array of HTML tags that will be ignored if clicked.
+     */
+    invalidHandleTypes: null,
+
+    /**
+     * The linked element's absolute X position at the time the drag was
+     * started
+     *
+     * @type int
+     * @private
+     */
+    startPageX: 0,
+
+    /**
+     * The linked element's absolute X position at the time the drag was
+     * started
+     *
+     * @type int
+     * @private
+     */
+    startPageY: 0,
+
+    /**
+     * The group defines a logical collection of DragDrop objects that are
+     * related.  Instances only get events when interacting with other
+     * DragDrop object in the same group.  This lets us define multiple
+     * groups using a single DragDrop subclass if we want.
+     *
+     */
+    groups: null,
+
+    /**
+     * Individual drag/drop instances can be locked.  This will prevent
+     * onmousedown start drag.
+     *
+     * @type boolean
+     * @private
+     */
+    locked: false,
+
+    /**
+     * Lock this instance
+     */
+    lock: function() { this.locked = true; },
+
+    /**
+     * Unlock this instace
+     */
+    unlock: function() { this.locked = false; },
+
+    /**
+     * By default, all insances can be a drop target.  This can be disabled by
+     * setting isTarget to false.
+     *
+     * @type boolean
+     */
+    isTarget: true,
+
+    /**
+     * The padding configured for this drag and drop object for calculating
+     * the drop zone intersection with this object.
+     */
+    padding: null,
+
+    /**
+     * @private
+     */
+    _domRef: null,
+
+    /**
+     * Internal typeof flag
+     * @private
+     */
+    __ygDragDrop: true,
+
+    /**
+     * Set to true when horizontal contraints are applied
+     *
+     * @type boolean
+     * @private
+     */
+    constrainX: false,
+
+    /**
+     * Set to true when vertical contraints are applied
+     *
+     * @type boolean
+     * @private
+     */
+    constrainY: false,
+
+    /**
+     * The left constraint
+     *
+     * @type int
+     * @private
+     */
+    minX: 0,
+
+    /**
+     * The right constraint
+     *
+     * @type int
+     * @private
+     */
+    maxX: 0,
+
+    /**
+     * The up constraint
+     *
+     * @type int
+     * @private
+     */
+    minY: 0,
+
+    /**
+     * The down constraint
+     *
+     * @type int
+     * @private
+     */
+    maxY: 0,
+
+    /**
+     * Maintain offsets when we resetconstraints.  Used to maintain the
+     * slider thumb value, and this needs to be fixed.
+     * @type boolean
+     */
+    maintainOffset: false,
+
+    /**
+     * Array of pixel locations the element will snap to if we specified a
+     * horizontal graduation/interval.  This array is generated automatically
+     * when you define a tick interval.
+     * @type int[]
+     */
+    xTicks: null,
+
+    /**
+     * Array of pixel locations the element will snap to if we specified a
+     * vertical graduation/interval.  This array is generated automatically
+     * when you define a tick interval.
+     * @type int[]
+     */
+    yTicks: null,
+
+    /**
+     * By default the drag and drop instance will only respond to the primary
+     * button click (left button for a right-handed mouse).  Set to true to
+     * allow drag and drop to start with any mouse click that is propogated
+     * by the browser
+     * @type boolean
+     */
+    primaryButtonOnly: true,
+
+    /**
+     * Code that executes immediately before the startDrag event
+     * @private
+     */
+    b4StartDrag: function(x, y) { },
+
+    /**
+     * Abstract method called after a drag/drop object is clicked
+     * and the drag or mousedown time thresholds have beeen met.
+     *
+     * @param {int} X click location
+     * @param {int} Y click location
+     */
+    startDrag: function(x, y) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDrag event
+     * @private
+     */
+    b4Drag: function(e) { },
+
+    /**
+     * Abstract method called during the onMouseMove event while dragging an
+     * object.
+     *
+     * @param {Event} e
+     */
+    onDrag: function(e) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragEnter event
+     * @private
+     */
+    // b4DragEnter: function(e) { },
+
+    /**
+     * Abstract method called when this element fist begins hovering over
+     * another DragDrop obj
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this is hovering over.  In INTERSECT mode, an array of one or more
+     * dragdrop items being hovered over.
+     */
+    onDragEnter: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragOver event
+     * @private
+     */
+    b4DragOver: function(e) { },
+
+    /**
+     * Abstract method called when this element is hovering over another
+     * DragDrop obj
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this is hovering over.  In INTERSECT mode, an array of dd items
+     * being hovered over.
+     */
+    onDragOver: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragOut event
+     * @private
+     */
+    b4DragOut: function(e) { },
+
+    /**
+     * Abstract method called when we are no longer hovering over an element
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this was hovering over.  In INTERSECT mode, an array of dd items
+     * that the mouse is no longer over.
+     */
+    onDragOut: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragDrop event
+     * @private
+     */
+    b4DragDrop: function(e) { },
+
+    /**
+     * Abstract method called when this item is dropped on another DragDrop
+     * obj
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this was dropped on.  In INTERSECT mode, an array of dd items this
+     * was dropped on.
+     */
+    onDragDrop: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the endDrag event
+     * @private
+     */
+    b4EndDrag: function(e) { },
+
+    /**
+     * Fired when we are done dragging the object
+     *
+     * @param {Event} e
+     */
+    endDrag: function(e) { /* override this */ },
+
+    /**
+     * Code executed immediately before the onMouseDown event
+
+     * @param {Event} e
+     * @private
+     */
+    b4MouseDown: function(e) {  },
+
+    /**
+     * Event handler that fires when a drag/drop obj gets a mousedown
+     * @param {Event} e
+     */
+    onMouseDown: function(e) { /* override this */ },
+
+    /**
+     * Event handler that fires when a drag/drop obj gets a mouseup
+     * @param {Event} e
+     */
+    onMouseUp: function(e) { /* override this */ },
+
+    /**
+     * Returns a reference to the linked element
+     *
+     * @return {Object} the html element
+     */
+    getEl: function() {
+        if (!this._domRef) {
+            this._domRef = this.DDM.getElement(this.id);
+        }
+
+        return this._domRef;
+    },
+
+    /**
+     * Returns a reference to the actual element to drag.  By default this is
+     * the same as the html element, but it can be assigned to another
+     * element. An example of this can be found in YAHOO.util.DDProxy
+     *
+     * @return {Object} the html element
+     */
+    getDragEl: function() {
+        return this.DDM.getElement(this.dragElId);
+    },
+
+    /**
+     * Sets up the DragDrop object.  Must be called in the constructor of any
+     * YAHOO.util.DragDrop subclass
+     *
+     * @param id the id of the linked element
+     * @param {String} sGroup the group of related items
+     * element is supposed to be a target only, set to false.
+     */
+    init: function(id, sGroup) {
+        this.initTarget(id, sGroup);
+        YAHOO.util.Event.addListener(id, "mousedown",
+                                          this.handleMouseDown, this, true);
+    },
+
+    /**
+     * Initializes Targeting functionality only... the object does not
+     * get a mousedown handler.
+     *
+     * @param id the id of the linked element
+     * @param {String} sGroup the group of related items
+     * element is supposed to be a target only, set to false.
+     */
+    initTarget: function(id, sGroup) {
+
+        // create a local reference to the drag and drop manager
+        this.DDM = YAHOO.util.DDM;
+
+        // create a logger instance
+        this.logger = new ygLogger("DragDrop");
+
+        // set the default padding
+        this.padding = [0, 0, 0, 0];
+
+        // initialize the groups array
+        this.groups = {};
+
+        // set the id
+        this.id = id;
+
+        // the element is a drag handle by default
+        this.setDragElId(id);
+
+        // by default, clicked anchors will not start drag operations
+        this.invalidHandleTypes = {a : "a"};
+
+        // We don't want to register this as the handle with the manager
+        // so we just set the id rather than calling the setter
+        this.handleElId = id;
+
+        // cache the position of the element if we can
+        if (document && document.body) {
+            this.setInitPosition();
+        }
+
+        // add to an interaction group
+        this.addToGroup((sGroup) ? sGroup : "default");
+
+    },
+
+    /**
+     * Configures the padding for the target zone in px.  Effectively expands
+     * (or reduces) the virtual object size for targeting calculations.
+     * Supports css-style shorthand; if only one parameter is passed, all sides
+     * will have that padding, and if only two are passed, the top and bottom
+     * will have the first param, the left and right the second.
+     * @param {int} iTop    Top pad
+     * @param {int} iRight  Right pad
+     * @param {int} iBot    Bot pad
+     * @param {int} iLeft   Left pad
+     */
+    setPadding: function(iTop, iRight, iBot, iLeft) {
+        // this.padding = [iLeft, iRight, iTop, iBot];
+        if (!iRight && 0 !== iRight) {
+            this.padding = [iTop, iTop, iTop, iTop];
+        } else if (!iBot && 0 !== iBot) {
+            this.padding = [iTop, iRight, iTop, iRight];
+        } else {
+            this.padding = [iTop, iRight, iBot, iLeft];
+        }
+    },
+
+    /**
+     * Stores the initial placement of the dd element
+     */
+    setInitPosition: function(diffX, diffY) {
+        var el = this.getEl();
+
+        if (!this.DDM.verifyEl(el)) {
+            this.logger.debug(this.id + " element is broken");
+            return;
+        }
+
+        var dx = diffX || 0;
+        var dy = diffY || 0;
+
+        var p = YAHOO.util.Dom.getXY( el );
+
+        this.initPageX = p[0] - dx;
+        this.initPageY = p[1] - dy;
+
+        this.lastPageX = p[0];
+        this.lastPageY = p[1];
+
+        this.setStartPosition(p);
+    },
+
+    /**
+     * Sets the start position of the element.  This is set when the obj
+     * is initialized, the reset when a drag is started.
+     * @param pos current position (from previous lookup)
+     * @private
+     */
+    setStartPosition: function(pos) {
+
+        var p = pos || YAHOO.util.Dom.getXY( this.getEl() );
+
+        this.startPageX = p[0];
+        this.startPageY = p[1];
+    },
+
+    /**
+     * Add this instance to a group of related drag/drop objects.  All
+     * instances belong to at least one group, and can belong to as many
+     * groups as needed.
+     *
+     * @param sGroup {string} the name of the group
+     */
+    addToGroup: function(sGroup) {
+        this.groups[sGroup] = true;
+        this.DDM.regDragDrop(this, sGroup);
+    },
+
+    /**
+     * Allows you to specify that an element other than the linked element
+     * will be moved with the cursor during a drag
+     *
+     * @param id the id of the element that will be used to initiate the drag
+     */
+    setDragElId: function(id) {
+        this.dragElId = id;
+    },
+
+    /**
+     * Allows you to specify a child of the linked element that should be
+     * used to initiate the drag operation.  An example of this would be if
+     * you have a content div with text and links.  Clicking anywhere in the
+     * content area would normally start the drag operation.  Use this method
+     * to specify that an element inside of the content div is the element
+     * that starts the drag operation.
+     *
+     * @param id the id of the element that will be used to initiate the drag
+     */
+    setHandleElId: function(id) {
+        this.handleElId = id;
+        this.DDM.regHandle(this.id, id);
+    },
+
+    /**
+     * Allows you to set an element outside of the linked element as a drag
+     * handle
+     */
+    setOuterHandleElId: function(id) {
+        this.logger.debug("Adding outer handle event: " + id);
+        YAHOO.util.Event.addListener(id, "mousedown",
+                this.handleMouseDown, this, true);
+        this.setHandleElId(id);
+    },
+
+    /**
+     * Remove all drag and drop hooks for this element
+     */
+    unreg: function() {
+        this.logger.debug("DragDrop obj cleanup " + this.id);
+        YAHOO.util.Event.removeListener(this.id, "mousedown",
+                this.handleMouseDown);
+        this._domRef = null;
+        this.DDM._remove(this);
+    },
+
+    /**
+     * Returns true if this instance is locked, or the drag drop mgr is locked
+     * (meaning that all drag/drop is disabled on the page.)
+     *
+     * @return {boolean} true if this obj or all drag/drop is locked, else
+     * false
+     */
+    isLocked: function() {
+        return (this.DDM.isLocked() || this.locked);
+    },
+
+    /**
+     * Fired when this object is clicked
+     *
+     * @param {Event} e
+     * @param {YAHOO.util.DragDrop} oDD the clicked dd object (this dd obj)
+     * @private
+     */
+    handleMouseDown: function(e, oDD) {
+
+        this.logger.debug("isLocked: " + this.isLocked());
+
+        var EU = YAHOO.util.Event;
+
+
+        var button = e.which || e.button;
+        this.logger.debug("button: " + button);
+
+        if (this.primaryButtonOnly && button > 1) {
+            this.logger.debug("Mousedown was not produced by the primary button");
+            return;
+        }
+
+        if (this.isLocked()) {
+            this.logger.debug("Drag and drop is disabled, aborting");
+            return;
+        }
+
+        this.logger.debug("mousedown " + this.id);
+
+        this.DDM.refreshCache(this.groups);
+
+        // Only process the event if we really clicked within the linked
+        // element.  The reason we make this check is that in the case that
+        // another element was moved between the clicked element and the
+        // cursor in the time between the mousedown and mouseup events. When
+        // this happens, the element gets the next mousedown event
+        // regardless of where on the screen it happened.
+        var pt = new YAHOO.util.Point(EU.getPageX(e), EU.getPageY(e));
+        if ( this.DDM.isOverTarget(pt, this) )  {
+
+            this.logger.debug("click is legit");
+
+            //  check to see if the handle was clicked
+            var srcEl = EU.getTarget(e);
+
+            if (this.isValidHandleChild(srcEl) &&
+                    (this.id == this.handleElId ||
+                     this.DDM.handleWasClicked(srcEl, this.id)) ) {
+
+                // set the initial element position
+                this.setStartPosition();
+
+                this.logger.debug("firing onMouseDown events");
+
+
+                this.b4MouseDown(e);
+                this.onMouseDown(e);
+                this.DDM.handleMouseDown(e, this);
+
+                this.DDM.stopEvent(e);
+            }
+        }
+    },
+
+    /**
+     * Allows you to specify a tag name that should not start a drag operation
+     * when clicked.  This is designed to facilitate embedding links within a
+     * drag handle that do something other than start the drag.
+     *
+     * @param {string} tagName the type of element to exclude
+     */
+    addInvalidHandleType: function(tagName) {
+        var type = tagName.toUpperCase();
+        this.invalidHandleTypes[type] = type;
+    },
+
+    /**
+     * Unsets an excluded tag name set by addInvalidHandleType
+     *
+     * @param {string} tagName the type of element to unexclude
+     */
+    removeInvalidHandleType: function(tagName) {
+        var type = tagName.toUpperCase();
+        this.invalidHandleTypes[type] = null;
+    },
+
+    /**
+     * Checks the tag exclusion list to see if this click should be ignored
+     *
+     * @param {ygNode} node
+     * @return {boolean} true if this is a valid tag type, false if not
+     */
+    isValidHandleChild: function(node) {
+        var type = node.nodeName;
+
+        if (type == "#text") {
+            // this.logger.debug("text node, getting parent node type");
+            type = node.parentNode.nodeName;
+        }
+
+        return (!this.invalidHandleTypes[type]);
+    },
+
+    /**
+     * Create the array of horizontal tick marks if an interval was specified
+     * in setXConstraint().
+     *
+     * @private
+     */
+    setXTicks: function(iStartX, iTickSize) {
+        this.xTicks = [];
+        this.xTickSize = iTickSize;
+
+        var tickMap = {};
+
+        for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
+            if (!tickMap[i]) {
+                this.xTicks[this.xTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
+            if (!tickMap[i]) {
+                this.xTicks[this.xTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        this.xTicks.sort(this.DDM.numericSort) ;
+        this.logger.debug("xTicks: " + this.xTicks.join());
+    },
+
+    /**
+     * Create the array of vertical tick marks if an interval was specified in
+     * setYConstraint().
+     *
+     * @private
+     */
+    setYTicks: function(iStartY, iTickSize) {
+        this.yTicks = [];
+        this.yTickSize = iTickSize;
+
+        var tickMap = {};
+
+        for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
+            if (!tickMap[i]) {
+                this.yTicks[this.yTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
+            if (!tickMap[i]) {
+                this.yTicks[this.yTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        this.yTicks.sort(this.DDM.numericSort) ;
+        this.logger.debug("yTicks: " + this.yTicks.join());
+    },
+
+    /**
+     * By default, the element can be dragged any place on the screen.  Use
+     * this method to limit the horizontal travel of the element.  Pass in
+     * 0,0 for the parameters if you want to lock the drag to the y axis.
+     *
+     * @param {int} iLeft the number of pixels the element can move to the left
+     * @param {int} iRight the number of pixels the element can move to the
+     * right
+     * @param {int} iTickSize optional parameter for specifying that the
+     * element
+     * should move iTickSize pixels at a time.
+     */
+    setXConstraint: function(iLeft, iRight, iTickSize) {
+        this.leftConstraint = iLeft;
+        this.rightConstraint = iRight;
+
+        this.minX = this.initPageX - iLeft;
+        this.maxX = this.initPageX + iRight;
+        if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
+
+        this.constrainX = true;
+        this.logger.debug("initPageX:" + this.initPageX + " minX:" + this.minX +
+                " maxX:" + this.maxX);
+    },
+
+    /**
+     * By default, the element can be dragged any place on the screen.  Set
+     * this to limit the vertical travel of the element.  Pass in 0,0 for the
+     * parameters if you want to lock the drag to the x axis.
+     *
+     * @param {int} iUp the number of pixels the element can move up
+     * @param {int} iDown the number of pixels the element can move down
+     * @param {int} iTickSize optional parameter for specifying that the
+     * element should move iTickSize pixels at a time.
+     */
+    setYConstraint: function(iUp, iDown, iTickSize) {
+        this.topConstraint = iUp;
+        this.bottomConstraint = iDown;
+
+        this.minY = this.initPageY - iUp;
+        this.maxY = this.initPageY + iDown;
+        if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
+
+        this.constrainY = true;
+
+        this.logger.debug("initPageY:" + this.initPageY + " minY:" + this.minY +
+                " maxY:" + this.maxY);
+    },
+
+    /**
+     * resetConstraints must be called if you manually reposition a dd element.
+     * @param {boolean} maintainOffset
+     */
+    resetConstraints: function() {
+
+        // this.logger.debug("init pagexy: " + this.initPageX + ", " +
+        //      this.initPageY);
+        // this.logger.debug("last pagexy: " + this.lastPageX + ", " +
+        //      this.lastPageY);
+
+        // figure out how much this thing has moved
+        var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
+        var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
+
+        // this.logger.debug("diff: " + dx + ", " + dy);
+
+        // reset the initial location
+        this.setInitPosition(dx, dy);
+
+        if (this.constrainX) {
+            this.setXConstraint( this.leftConstraint,
+                                 this.rightConstraint,
+                                 this.xTickSize        );
+        }
+
+        if (this.constrainY) {
+            this.setYConstraint( this.topConstraint,
+                                 this.bottomConstraint,
+                                 this.yTickSize         );
+        }
+    },
+
+    /**
+     * Normally the drag element is moved pixel by pixel, but we can specify
+     * that it move a number of pixels at a time.  This method resolves the
+     * location when we have it set up like this.
+     *
+     * @param {int} val where we want to place the object
+     * @param {int[]} tickArray sorted array of valid points
+     * @return {int} the closest tick
+     * @private
+     */
+    getTick: function(val, tickArray) {
+
+        if (!tickArray) {
+            // If tick interval is not defined, it is effectively 1 pixel,
+            // so we return the value passed to us.
+            return val;
+        } else if (tickArray[0] >= val) {
+            // The value is lower than the first tick, so we return the first
+            // tick.
+            return tickArray[0];
+        } else {
+            for (var i = 0; i < tickArray.length; ++i) {
+                var next = i + 1;
+                if (tickArray[next] && tickArray[next] >= val) {
+                    var diff1 = val - tickArray[i];
+                    var diff2 = tickArray[next] - val;
+                    return (diff2 > diff1) ? tickArray[i] : tickArray[next];
+                }
+            }
+
+            // The value is larger than the last tick, so we return the last
+            // tick.
+            return tickArray[tickArray.length - 1];
+        }
+    },
+
+    /**
+     * toString method
+     * @return {string} string representation of the dd obj
+     */
+    toString: function(val, tickArray) {
+        return ("YAHOO.util.DragDrop {" + this.id + "}");
+    }
+
+};
+
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+// Only load the library once.  Rewriting the manager class would orphan
+// existing drag and drop instances.
+if (!YAHOO.util.DragDropMgr) {
+
+    /**
+     * @class Handles the element interaction for all DragDrop items in the
+     * window.  Generally, you will not call this class directly, but it does
+     * have helper methods that could be useful in your DragDrop
+     * implementations.  This class should not be instantiated; all methods
+     * are are static.
+     *
+     * @constructor
+     */
+    YAHOO.util.DragDropMgr = new function() {
+
+        /**
+         * utility package shorthand
+         * @private
+         */
+        var UTIL = YAHOO.util;
+
+        /**
+         * Two dimensional Array of registered DragDrop objects.  The first
+         * dimension is the DragDrop item group, the second the DragDrop
+         * object.
+         *
+         * @private
+         */
+        this.ids = {};
+
+        /**
+         * Array of element ids defined as drag handles.  Used to determine
+         * if the element that generated the mousedown event is actually the
+         * handle and not the html element itself.
+         *
+         * @private
+         */
+        this.handleIds = {};
+
+        /**
+         * the DragDrop object that is currently being dragged
+         *
+         * @type DragDrop
+         * @private
+         **/
+        this.dragCurrent = null;
+
+        /**
+         * the DragDrop object(s) that are being hovered over
+         *
+         * @type Array
+         * @private
+         */
+        this.dragOvers = {};
+
+        /**
+         * @private
+         */
+        this.logger = null;
+
+        /**
+         * the X distance between the cursor and the object being dragged
+         *
+         * @type int
+         * @private
+         */
+        this.deltaX = 0;
+
+        /**
+         * the Y distance between the cursor and the object being dragged
+         *
+         * @type int
+         * @private
+         */
+        this.deltaY = 0;
+
+        /**
+         * Flag to determine if we should prevent the default behavior of the
+         * events we define. By default this is true, but this can be set to
+         * false if you need the default behavior (not recommended)
+         *
+         * @type boolean
+         */
+        this.preventDefault = true;
+
+        /**
+         * Flag to determine if we should stop the propagation of the events
+         * we generate. This is true by default but you may want to set it to
+         * false if the html element contains other features that require the
+         * mouse click.
+         *
+         * @type boolean
+         */
+        this.stopPropagation = true;
+
+        /**
+         * @private
+         */
+        this.initalized = false;
+
+        /**
+         * All drag and drop can be disabled.
+         *
+         * @private
+         */
+        this.locked = false;
+
+        /**
+         * Called the first time an element is registered.
+         *
+         * @private
+         */
+        this.init = function() {
+            this.logger = new ygLogger("DragDropMgr");
+        };
+
+        /**
+         * In point mode, drag and drop interaction is defined by the
+         * location of the cursor during the drag/drop
+         * @type int
+         */
+        this.POINT     = 0;
+
+        /**
+         * In intersect mode, drag and drop interactio nis defined by the
+         * overlap of two or more drag and drop objects.
+         * @type int
+         */
+        this.INTERSECT = 1;
+
+        /**
+         * The current drag and drop mode.  Default it point mode
+         * @type int
+         */
+        this.mode = this.POINT;
+
+        /**
+         * Runs method on all drag and drop objects
+         * @private
+         */
+        this._execOnAll = function(sMethod, args) {
+            for (var i in this.ids) {
+                for (var j in this.ids[i]) {
+                    var oDD = this.ids[i][j];
+                    if (! this.isTypeOfDD(oDD)) {
+                        continue;
+                    }
+                    oDD[sMethod].apply(oDD, args);
+                }
+            }
+        };
+
+        /**
+         * Drag and drop initialization.  Sets up the global event handlers
+         * @private
+         */
+        this._onLoad = function() {
+
+            this._execOnAll("setInitPosition", []);
+
+            this.logger = new ygLogger("DragDropMgr");
+            this.logger.debug("DDM onload");
+
+            var EU = UTIL.Event;
+
+            EU.addListener(document, "mouseup",   this.handleMouseUp, this, true);
+            EU.addListener(document, "mousemove", this.handleMouseMove, this, true);
+            EU.addListener(window,   "unload",    this._onUnload, this, true);
+            EU.addListener(window,   "resize",    this._onResize, this, true);
+            // EU.addListener(window,   "mouseout",    this._test);
+
+            this.initalized = true;
+
+        };
+
+        /**
+         * Reset constraints on all drag and drop objs
+         * @private
+         */
+        this._onResize = function(e) {
+            this.logger.debug("window resize");
+            this._execOnAll("resetConstraints", []);
+        };
+
+        /**
+         * Lock all drag and drop functionality
+         */
+        this.lock = function() { this.locked = true; };
+
+        /**
+         * Unlock all drag and drop functionality
+         */
+        this.unlock = function() { this.locked = false; };
+
+        /**
+         * Is drag and drop locked?
+         *
+         * @return {boolean} True if drag and drop is locked, false otherwise.
+         */
+        this.isLocked = function() { return this.locked; };
+
+        /**
+         * Location cache that is set for all drag drop objects when a drag is
+         * initiated, cleared when the drag is finished.
+         *
+         * @private
+         */
+        this.locationCache = {};
+
+        /**
+         * Set useCache to false if you want to force object the lookup of each
+         * drag and drop linked element constantly during a drag.
+         * @type boolean
+         */
+        this.useCache = true;
+
+        /**
+         * The number of pixels that the mouse needs to move after the
+         * mousedown before the drag is initiated.  Default=3;
+         * @type int
+         */
+        this.clickPixelThresh = 3;
+
+        /**
+         * The number of milliseconds after the mousedown event to initiate the
+         * drag if we don't get a mouseup event. Default=1000
+         * @type int
+         */
+        this.clickTimeThresh = 1000;
+
+        /**
+         * Flag that indicates that either the drag pixel threshold or the
+         * mousdown time threshold has been met
+         * @type boolean
+         * @private
+         */
+        this.dragThreshMet = false;
+
+        /**
+         * Timeout used for the click time threshold
+         * @type Object
+         * @private
+         */
+        this.clickTimeout = null;
+
+        /**
+         * The X position of the mousedown event stored for later use when a
+         * drag threshold is met.
+         * @type int
+         * @private
+         */
+        this.startX = 0;
+
+        /**
+         * The Y position of the mousedown event stored for later use when a
+         * drag threshold is met.
+         * @type int
+         * @private
+         */
+        this.startY = 0;
+
+        /**
+         * Each DragDrop instance must be registered with the DragDropMgr.
+         * This is executed in ygDragDrop.init()
+         *
+         * @param {DragDrop} oDD the DragDrop object to register
+         * @param {String} sGroup the name of the group this element belongs to
+         */
+        this.regDragDrop = function(oDD, sGroup) {
+            if (!this.initialized) { this.init(); }
+
+            if (!this.ids[sGroup]) {
+                this.ids[sGroup] = {};
+            }
+            this.ids[sGroup][oDD.id] = oDD;
+        };
+
+        /**
+         * Unregisters a drag and drop item.  This is executed in
+         * ygDragDrop.unreg, use that method instead of calling this directly.
+         * @private
+         */
+        this._remove = function(oDD) {
+            for (var g in oDD.groups) {
+                if (g && this.ids[g][oDD.id]) {
+                    delete this.ids[g][oDD.id];
+                }
+            }
+            delete this.handleIds[oDD.id];
+        };
+
+        /**
+         * Each DragDrop handle element must be registered.  This is done
+         * automatically when executing ygDragDrop.setHandleElId()
+         *
+         * @param {String} sDDId the DragDrop id this element is a handle for
+         * @param {String} sHandleId the id of the element that is the drag
+         * handle
+         */
+        this.regHandle = function(sDDId, sHandleId) {
+            if (!this.handleIds[sDDId]) {
+                this.handleIds[sDDId] = {};
+            }
+            this.handleIds[sDDId][sHandleId] = sHandleId;
+        };
+
+        /**
+         * Utility function to determine if a given element has been
+         * registered as a drag drop item.
+         *
+         * @param {String} id the element id to check
+         * @return {boolean} true if this element is a DragDrop item,
+         * false otherwise
+         */
+        this.isDragDrop = function(id) {
+            return ( this.getDDById(id) ) ? true : false;
+        };
+
+        /**
+         * Returns the drag and drop instances that are in all groups the
+         * passed in instance belongs to.
+         *
+         * @param {ygDragDrop} p_oDD the obj to get related data for
+         * @param {boolean} bTargetsOnly if true, only return targetable objs
+         * @return {ygDragDrop[]} the related instances
+         */
+        this.getRelated = function(p_oDD, bTargetsOnly) {
+            var oDDs = [];
+            for (var i in p_oDD.groups) {
+                for (j in this.ids[i]) {
+                    var dd = this.ids[i][j];
+                    if (! this.isTypeOfDD(dd)) {
+                        continue;
+                    }
+                    if (!bTargetsOnly || dd.isTarget) {
+                        oDDs[oDDs.length] = dd;
+                    }
+                }
+            }
+
+            return oDDs;
+        };
+
+        /**
+         * Returns true if the specified dd target is a legal target for
+         * the specifice drag obj
+         *
+         * @param {ygDragDrop} the drag obj
+         * @param {ygDragDrop) the target
+         * @return {boolean} true if the target is a legal target for the
+         * dd obj
+         */
+        this.isLegalTarget = function (oDD, oTargetDD) {
+            var targets = this.getRelated(oDD);
+            for (var i =0;i<targets.length;++i) {
+                if (targets[i].id == oTargetDD.id) {
+                    return true;
+                }
+            }
+
+            return false;
+        };
+
+        /**
+         * My goal is to be able to transparently determine if an object is
+         * typeof ygDragDrop, and the exact subclass of ygDragDrop.  typeof
+         * returns "object", oDD.constructor.toString() always returns
+         * "ygDragDrop" and not the name of the subclass.  So for now it just
+         * evaluates a well-known variable in ygDragDrop.
+         *
+         * @param {Object} the object to evaluate
+         * @return {boolean} true if typeof oDD = ygDragDrop
+         */
+        this.isTypeOfDD = function (oDD) {
+            return (oDD && oDD.__ygDragDrop);
+        };
+
+        /**
+         * Utility function to determine if a given element has been
+         * registered as a drag drop handle for the given Drag Drop object.
+         *
+         * @param {String} id the element id to check
+         * @return {boolean} true if this element is a DragDrop handle, false
+         * otherwise
+         */
+        this.isHandle = function(sDDId, sHandleId) {
+            return ( this.handleIds[sDDId] &&
+                            this.handleIds[sDDId][sHandleId] );
+        };
+
+        /**
+         * Returns the DragDrop instance for a given id
+         *
+         * @param {String} id the id of the DragDrop object
+         * @return {DragDrop} the drag drop object, null if it is not found
+         */
+        this.getDDById = function(id) {
+            for (var i in this.ids) {
+                if (this.ids[i][id]) {
+                    return this.ids[i][id];
+                }
+            }
+            return null;
+        };
+
+        /**
+         * Fired after a registered DragDrop object gets the mousedown event.
+         * Sets up the events required to track the object being dragged
+         *
+         * @param {Event} e the event
+         * @param oDD the DragDrop object being dragged
+         * @private
+         */
+        this.handleMouseDown = function(e, oDD) {
+            this.logger.debug("mousedown - adding event handlers");
+            this.dragCurrent = oDD;
+
+            var el = oDD.getEl();
+
+            // track start position
+            this.startX = UTIL.Event.getPageX(e);
+            this.startY = UTIL.Event.getPageY(e);
+
+            this.deltaX = this.startX - el.offsetLeft;
+            this.deltaY = this.startY - el.offsetTop;
+
+            this.dragThreshMet = false;
+
+            this.clickTimeout = setTimeout(
+               "var DDM=YAHOO.util.DDM;DDM.startDrag(DDM.startX, DDM.startY)",
+               this.clickTimeThresh );
+        };
+
+        /**
+         * Fired when either the drag pixel threshol or the mousedown hold
+         * time threshold has been met.
+         *
+         * @param x {int} the X position of the original mousedown
+         * @param y {int} the Y position of the original mousedown
+         */
+        this.startDrag = function(x, y) {
+            this.logger.debug("firing drag start events");
+            clearTimeout(this.clickTimeout);
+            if (this.dragCurrent) {
+                this.dragCurrent.b4StartDrag(x, y);
+                this.dragCurrent.startDrag(x, y);
+            }
+            this.dragThreshMet = true;
+        };
+
+        /**
+         * Internal function to handle the mouseup event.  Will be invoked
+         * from the context of the document.
+         *
+         * @param {Event} e the event
+         * @private
+         */
+        this.handleMouseUp = function(e) {
+
+            if (! this.dragCurrent) {
+                return;
+            }
+
+            clearTimeout(this.clickTimeout);
+
+            if (this.dragThreshMet) {
+                this.logger.debug("mouseup detected - completing drag");
+                this.fireEvents(e, true);
+            } else {
+                this.logger.debug("drag threshold not met");
+            }
+
+            this.stopDrag(e);
+
+            this.stopEvent(e);
+        };
+
+        /**
+         * Utility to stop event propagation and event default, if these
+         * features are turned on.
+         *
+         * @param {Event} e the event as returned by this.getEvent()
+         */
+        this.stopEvent = function(e) {
+            if (this.stopPropagation) {
+                UTIL.Event.stopPropagation(e);
+            }
+
+            if (this.preventDefault) {
+                UTIL.Event.preventDefault(e);
+            }
+        };
+
+        /**
+         * Internal function to clean up event handlers after the drag
+         * operation is complete
+         *
+         * @param {Event} e the event
+         * @private
+         */
+        this.stopDrag = function(e) {
+            // this.logger.debug("mouseup - removing event handlers");
+
+            // Fire the drag end event for the item that was dragged
+            if (this.dragCurrent) {
+                if (this.dragThreshMet) {
+                    this.logger.debug("firing endDrag events");
+                    this.dragCurrent.b4EndDrag(e);
+                    this.dragCurrent.endDrag(e);
+                }
+
+                this.logger.debug("firing onMouseUp event");
+                this.dragCurrent.onMouseUp(e);
+            }
+
+            this.dragCurrent = null;
+            this.dragOvers = {};
+        };
+
+
+        /**
+         * Internal function to handle the mousemove event.  Will be invoked
+         * from the context of the html element.
+         *
+         * @TODO figure out what we can do about mouse events lost when the
+         * user drags objects beyond the window boundary.  Currently we can
+         * detect this in internet explorer by verifying that the mouse is
+         * down during the mousemove event.  Firefox doesn't give us the
+         * button state on the mousemove event.
+         *
+         * @param {Event} e the event
+         * @private
+         */
+        this.handleMouseMove = function(e) {
+            if (! this.dragCurrent) {
+                // this.logger.debug("no current drag obj");
+                return;
+            }
+
+            // var button = e.which || e.button;
+
+            this.logger.debug("which: " + e.which + ", button: "+ e.button);
+
+
+            // check for IE mouseup outside of page boundary
+            if (UTIL.Event.isIE && !e.button) {
+                this.stopEvent(e);
+                return this.handleMouseUp(e);
+                // this.logger.debug("button failure");
+            }
+
+            if (!this.dragThreshMet) {
+                var diffX = Math.abs(this.startX - UTIL.Event.getPageX(e));
+                var diffY = Math.abs(this.startY - UTIL.Event.getPageY(e));
+                // this.logger.debug("diffX: " + diffX + "diffY: " + diffY);
+                if (diffX > this.clickPixelThresh ||
+                            diffY > this.clickPixelThresh) {
+                    this.logger.debug("pixel threshold met");
+                    this.startDrag(this.startX, this.startY);
+                }
+            }
+
+            if (this.dragThreshMet) {
+                this.dragCurrent.b4Drag(e);
+                this.dragCurrent.onDrag(e);
+                this.fireEvents(e, false);
+            }
+
+            this.stopEvent(e);
+        };
+
+        /**
+         * Iterates over all of the DragDrop elements to find ones we are
+         * hovering over or dropping on
+         *
+         * @param {Event} e the event
+         * @param {boolean} isDrop is this a drop op or a mouseover op?
+         * @private
+         */
+        this.fireEvents = function(e, isDrop) {
+            var dc = this.dragCurrent;
+
+            // If the user did the mouse up outside of the window, we could
+            // get here even though we have ended the drag.
+            if (!dc || dc.isLocked()) {
+                return;
+            }
+
+            var x = UTIL.Event.getPageX(e);
+            var y = UTIL.Event.getPageY(e);
+            var pt = new YAHOO.util.Point(x,y);
+
+            // cache the previous dragOver array
+            var oldOvers = [];
+
+            var outEvts   = [];
+            var overEvts  = [];
+            var dropEvts  = [];
+            var enterEvts = [];
+
+            // Check to see if the object we were hovering over is no longer
+            // being hovered over so we can fire the onDragOut event
+            for (var i in this.dragOvers) {
+
+                var ddo = this.dragOvers[i];
+
+                if (! this.isTypeOfDD(ddo)) {
+                    continue;
+                }
+
+                if (! this.isOverTarget(pt, ddo, this.mode)) {
+                    outEvts.push( ddo );
+                }
+
+                oldOvers[i] = true;
+                delete this.dragOvers[i];
+            }
+
+            for (var sGroup in dc.groups) {
+                // this.logger.debug("Processing group " + sGroup);
+
+                if ("string" != typeof sGroup) {
+                    continue;
+                }
+
+                for (i in this.ids[sGroup]) {
+                    var oDD = this.ids[sGroup][i];
+                    if (! this.isTypeOfDD(oDD)) {
+                        continue;
+                    }
+
+                    if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
+                        if (this.isOverTarget(pt, oDD, this.mode)) {
+                            // look for drop interactions
+                            if (isDrop) {
+                                dropEvts.push( oDD );
+                            // look for drag enter and drag over interactions
+                            } else {
+
+                                // initial drag over: dragEnter fires
+                                if (!oldOvers[oDD.id]) {
+                                    enterEvts.push( oDD );
+                                // subsequent drag overs: dragOver fires
+                                } else {
+                                    overEvts.push( oDD );
+                                }
+
+                                this.dragOvers[oDD.id] = oDD;
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (this.mode) {
+                if (outEvts.length > 0) {
+                    dc.b4DragOut(e, outEvts);
+                    dc.onDragOut(e, outEvts);
+                }
+
+                if (enterEvts.length > 0) {
+                    dc.onDragEnter(e, enterEvts);
+                }
+
+                if (overEvts.length > 0) {
+                    dc.b4DragOver(e, overEvts);
+                    dc.onDragOver(e, overEvts);
+                }
+
+                if (dropEvts.length > 0) {
+                    dc.b4DragDrop(e, dropEvts);
+                    dc.onDragDrop(e, dropEvts);
+                }
+
+            } else {
+                // fire dragout events
+                for (i=0; i < outEvts.length; ++i) {
+                    this.logger.debug(dc.id+" onDragOut: " + outEvts[i].id);
+                    dc.b4DragOut(e, outEvts[i].id);
+                    dc.onDragOut(e, outEvts[i].id);
+                }
+
+                // fire enter events
+                for (i=0; i < enterEvts.length; ++i) {
+                    this.logger.debug(dc.id + " dragEnter " + enterEvts[i].id);
+                    // dc.b4DragEnter(e, oDD.id);
+                    dc.onDragEnter(e, enterEvts[i].id);
+                }
+
+                // fire over events
+                for (i=0; i < overEvts.length; ++i) {
+                    this.logger.debug(dc.id + " dragOver " + overEvts[i].id);
+                    dc.b4DragOver(e, overEvts[i].id);
+                    dc.onDragOver(e, overEvts[i].id);
+                }
+
+                // fire drop events
+                for (i=0; i < dropEvts.length; ++i) {
+                    this.logger.debug(dc.id + " dragDrop " + dropEvts[i].id);
+                    dc.b4DragDrop(e, dropEvts[i].id);
+                    dc.onDragDrop(e, dropEvts[i].id);
+                }
+
+            }
+
+        };
+
+        /**
+         * Helper function for getting the best match from the list of drag
+         * and drop objects returned by the drag and drop events when we are
+         * in INTERSECT mode.  It returns either the first object that the
+         * cursor is over, or the object that has the greatest overlap with
+         * the dragged element.
+         *
+         * @param  {ygDragDrop[]} dds The array of drag and drop objects
+         * targeted
+         * @return {ygDragDrop}       The best single match
+         */
+        this.getBestMatch = function(dds) {
+            var winner = null;
+            // Return null if the input is not what we expect
+            //if (!dds || !dds.length || dds.length == 0) {
+               // winner = null;
+            // If there is only one item, it wins
+            //} else if (dds.length == 1) {
+
+            if (dds.length == 1) {
+                winner = dds[0];
+            } else {
+                // Loop through the targeted items
+                for (var i=0; i<dds.length; ++i) {
+                    var dd = dds[i];
+                    // If the cursor is over the object, it wins.  If the
+                    // cursor is over multiple matches, the first one we come
+                    // to wins.
+                    if (dd.cursorIsOver) {
+                        winner = dd;
+                        break;
+                    // Otherwise the object with the most overlap wins
+                    } else {
+                        if (!winner ||
+                            winner.overlap.getArea() < dd.overlap.getArea()) {
+                            winner = dd;
+                        }
+                    }
+                }
+            }
+
+            return winner;
+        };
+
+        /**
+         * Refreshes the cache of the top-left and bottom-right points of the
+         * drag and drop objects in the specified groups
+         *
+         * @param {Array} aGroups an associative array of groups to refresh
+         */
+        this.refreshCache = function(aGroups) {
+            this.logger.debug("refreshing element location cache");
+            for (sGroup in aGroups) {
+                if ("string" != typeof sGroup) {
+                    continue;
+                }
+                for (i in this.ids[sGroup]) {
+                    var oDD = this.ids[sGroup][i];
+
+                    if (this.isTypeOfDD(oDD)) {
+                        var loc = this.getLocation(oDD);
+                        if (loc) {
+                            this.locationCache[oDD.id] = loc;
+                        } else {
+                            delete this.locationCache[oDD.id];
+                            this.logger.debug("something is wrong with the element");
+                            // this will unregister the drag and drop object if
+                            // the element is not in a usable state
+                            oDD.unreg();
+                        }
+                    }
+                }
+            }
+        };
+
+        /**
+         * This checks to make sure an element exists and is in the DOM.  The
+         * main purpose is to handle cases where innerHTML is used to remove
+         * drag and drop objects from the DOM.  IE provides an 'unspecified
+         * error' when trying to access the offsetParent of such an element
+         * @param {HTMLElement} el the element to check
+         * @return {boolean} true if the element looks usable
+         */
+        this.verifyEl = function(el) {
+            try {
+                if (el) {
+                    var parent = el.offsetParent;
+                    if (parent) {
+                        return true;
+                    }
+                }
+            } catch(e) {
+                this.logger.debug("detected problem with an element");
+            }
+
+            return false;
+        };
+
+        /**
+         * Returns the an array containing the drag and drop element's position
+         * and size, including the ygDragDrop.padding configured for it
+         *
+         * @param {ygDragDrop} oDD the drag and drop object to get the
+         * location for
+         * @return array containing the top left and bottom right points of the
+         * element
+         */
+        this.getLocation = function(oDD) {
+            if (! this.isTypeOfDD(oDD)) {
+                this.logger.debug(oDD + " is not a DD obj");
+                return null;
+            }
+
+            var el = oDD.getEl();
+
+            if (!this.verifyEl(el)) {
+                this.logger.debug(oDD + " element is not usable");
+                return null;
+            }
+
+            // this.logger.debug(oDD.id + " padding: " + oDD.padding);
+
+            // var aPos = ygPos.getPos(el);
+            var aPos = YAHOO.util.Dom.getXY(el);
+
+            x1 = aPos[0];
+            x2 = x1 + el.offsetWidth;
+
+            y1 = aPos[1];
+            y2 = y1 + el.offsetHeight;
+
+            var t = y1 - oDD.padding[0];
+            var r = x2 + oDD.padding[1];
+            var b = y2 + oDD.padding[2];
+            var l = x1 - oDD.padding[3];
+
+            return new YAHOO.util.Region( t, r, b, l );
+
+        };
+
+        /**
+         * Checks the cursor location to see if it over the target
+         *
+         * @param {YAHOO.util.Point} pt The point to evaluate
+         * @param {ygDragDrop} oDDTarget the DragDrop object we are inspecting
+         * @return {boolean} true if the mouse is over the target
+         * @private
+         */
+        this.isOverTarget = function(pt, oDDTarget, intersect) {
+            // use cache if available
+            var loc = this.locationCache[oDDTarget.id];
+            if (!loc || !this.useCache) {
+                this.logger.debug("cache not populated");
+                loc = this.getLocation(oDDTarget);
+                this.locationCache[oDDTarget.id] = loc;
+
+                this.logger.debug("cache: " + loc);
+            }
+
+            // this.logger.debug("isOverTarget: " + x + "," + y + ", " + loc);
+
+            // var cursorIsOver =  (x >= loc[3] && x <= loc[1] && y >= loc[0] && y <= loc[2]);
+            //oDDTarget.cursorIsOver = loc.contains( new YAHOO.util.Point(x, y) );
+            oDDTarget.cursorIsOver = loc.contains( pt );
+            oDDTarget.overlap = null;
+
+            // if (this.INTERSECT == this.mode) {
+            if (intersect) {
+
+                var curRegion =
+                    YAHOO.util.Region.getRegion(this.dragCurrent.getDragEl());
+                var overlap = curRegion.intersect(loc);
+
+                if (overlap) {
+                    oDDTarget.overlap = overlap;
+                    return true;
+                } else {
+                    return false;
+                }
+
+            } else {
+                return oDDTarget.cursorIsOver;
+            }
+        };
+
+        /**
+         * @private
+         */
+        this._onUnload = function(e, me) {
+            this.unregAll();
+        };
+
+        /**
+         * Cleans up the drag and drop events and objects.
+         *
+         * @private
+         */
+        this.unregAll = function() {
+            this.logger.debug("unregister all");
+
+            if (this.dragCurrent) {
+                this.stopDrag();
+                this.dragCurrent = null;
+            }
+
+            this._execOnAll("unreg", []);
+
+            for (i in this.elementCache) {
+                delete this.elementCache[i];
+            }
+
+            this.elementCache = {};
+            this.ids = {};
+        };
+
+        /**
+         * A cache of DOM elements
+         *
+         * @private
+         */
+        this.elementCache = {};
+
+        /**
+         * Get the wrapper for the DOM element specified
+         *
+         * @param {String} id the id of the elment to get
+         * @return {YAHOO.util.DDM.ElementWrapper} the wrapped element
+         * @private
+         */
+        this.getElWrapper = function(id) {
+            var oWrapper = this.elementCache[id];
+            if (!oWrapper || !oWrapper.el) {
+                // this.logger.debug("adding element cache: " + id);
+                oWrapper = this.elementCache[id] =
+                    new this.ElementWrapper(document.getElementById(id));
+            }
+            return oWrapper;
+        };
+
+        /**
+         * Returns the actual DOM element
+         *
+         * @param {String} id the id of the elment to get
+         * @return {Object} The element
+         */
+        this.getElement = function(id) {
+            // return this.getElWrapper(id).el;
+            return document.getElementById(id);
+        };
+
+        /**
+         * Returns the style property for the DOM element (i.e.,
+         * document.getElById(id).style)
+         *
+         * @param {String} id the id of the elment to get
+         * @return {Object} The style property of the element
+         */
+        this.getCss = function(id) {
+            // return this.getElWrapper(id).css;
+            var css = null;
+            var el = document.getElementById(id);
+            if (el) {
+                css = el.style;
+            }
+
+            return css;
+        };
+
+        /**
+         * Inner class for cached elements
+         */
+        this.ElementWrapper = function(el) {
+                /**
+                 * @private
+                 */
+                this.el = el || null;
+                /**
+                 * @private
+                 */
+                this.id = this.el && el.id;
+                /**
+                 * @private
+                 */
+                this.css = this.el && el.style;
+            };
+
+        /**
+         * Returns the X position of an html element
+         * @param el the element for which to get the position
+         * @return {int} the X coordinate
+         */
+        this.getPosX = function(el) {
+            return YAHOO.util.Dom.getX(el);
+        };
+
+        /**
+         * Returns the Y position of an html element
+         * @param el the element for which to get the position
+         * @return {int} the Y coordinate
+         */
+        this.getPosY = function(el) {
+            return YAHOO.util.Dom.getY(el);
+        };
+
+        /**
+         * Swap two nodes.  In IE, we use the native method, for others we
+         * emulate the IE behavior
+         *
+         * @param n1 the first node to swap
+         * @param n2 the other node to swap
+         */
+        this.swapNode = function(n1, n2) {
+            if (n1.swapNode) {
+                n1.swapNode(n2);
+            } else {
+                // the node reference order for the swap is a little tricky.
+                var p = n2.parentNode;
+                var s = n2.nextSibling;
+                n1.parentNode.replaceChild(n2,n1);
+                p.insertBefore(n1,s);
+            }
+        };
+
+        /**
+         * @private
+         */
+        this.getScroll = function () {
+            var t, l;
+            if (document.documentElement && document.documentElement.scrollTop) {
+                t = document.documentElement.scrollTop;
+                l = document.documentElement.scrollLeft;
+            } else if (document.body) {
+                t = document.body.scrollTop;
+                l = document.body.scrollLeft;
+            }
+            return { top: t, left: l };
+        };
+
+        /**
+         * Returns the specified element style property
+         * @param {HTMLElement} el          the element
+         * @param {string}      styleProp   the style property
+         * @return {string}     The value of the style property
+         */
+        this.getStyle = function(el, styleProp) {
+            if (el.style.styleProp) {
+                return el.style.styleProp;
+            } else if (el.currentStyle) {
+                return el.currentStyle[styleProp];
+            } else if (document.defaultView) {
+                return document.defaultView.getComputedStyle(el, null).
+                    getPropertyValue(styleProp);
+            }
+        };
+
+        /**
+         * Gets the scrollTop
+         *
+         * @return {int} the document's scrollTop
+         */
+        this.getScrollTop = function () { return this.getScroll().top; };
+
+        /**
+         * Gets the scrollLeft
+         *
+         * @return {int} the document's scrollTop
+         */
+        this.getScrollLeft = function () { return this.getScroll().left; };
+
+        this.moveToEl = function (moveEl, targetEl) {
+            var aCoord = YAHOO.util.Dom.getXY(targetEl);
+            this.logger.debug("moveToEl: " + aCoord);
+            YAHOO.util.Dom.setXY(moveEl, aCoord);
+        };
+
+        /**
+         * Gets the client height
+         *
+         * @return {int} client height in px
+         */
+        this.getClientHeight = function() {
+            return (window.innerHeight) ? window.innerHeight :
+                (document.documentElement && document.documentElement.clientHeight) ?
+                document.documentElement.clientHeight : document.body.offsetHeight;
+        };
+
+        /**
+         * Gets the client width
+         *
+         * @return {int} client width in px
+         */
+        this.getClientWidth = function() {
+            return (window.innerWidth) ? window.innerWidth :
+                (document.documentElement && document.documentElement.clientWidth) ?
+                document.documentElement.clientWidth : document.body.offsetWidth;
+        };
+
+        /**
+         * numeric array sort function
+         */
+        this.numericSort = function(a, b) { return (a - b); };
+
+        /**
+         * @private
+         */
+        this._timeoutCount = 0;
+
+        /**
+         * @private
+         * Trying to make the load order less important.  Without this we get
+         * an error if this file is loaded before the Event Utility.
+         */
+        this._addListeners = function() {
+            if ( UTIL.Event &&
+                 document          &&
+                 document.body        ) {
+
+                this._onLoad();
+            } else {
+                if (this._timeoutCount > 500) {
+                    this.logger.debug("DragDrop requires the Event Utility");
+                } else {
+                    setTimeout("YAHOO.util.DDM._addListeners()", 10);
+                    this._timeoutCount += 1;
+                }
+            }
+
+        };
+
+        /**
+         * Recursively searches the immediate parent and all child nodes for
+         * the handle element in order to determine wheter or not it was
+         * clicked.
+         *
+         * @param node the html element to inspect
+         */
+        this.handleWasClicked = function(node, id) {
+            if (this.isHandle(id, node.id)) {
+                this.logger.debug("clicked node is a handle");
+                return true;
+            } else {
+                // check to see if this is a text node child of the one we want
+                var p = node.parentNode;
+                // this.logger.debug("p: " + p);
+
+                while (p) {
+                    if (this.isHandle(id, p.id)) {
+                        return true;
+                    } else {
+                        this.logger.debug(p.id + " is not a handle");
+                        p = p.parentNode;
+                    }
+                }
+            }
+
+            return false;
+        };
+
+    };
+
+    // shorter alias, save a few bytes
+    YAHOO.util.DDM = YAHOO.util.DragDropMgr;
+    YAHOO.util.DDM._addListeners();
+
+}
+
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+/**
+ * @class a DragDrop implementation where the linked element follows the
+ * mouse cursor.
+ *
+ * @extends DragDrop
+ * @constructor
+ * @param {String} id the id of the linked element
+ * @param {String} sGroup the group of related DragDrop items
+ */
+YAHOO.util.DD = function(id, sGroup) {
+    if (id) {
+        this.init(id, sGroup);
+        this.logger.setModuleName("DD");
+    }
+};
+
+YAHOO.util.DD.prototype = new YAHOO.util.DragDrop();
+
+/**
+ * Should we auto-scroll? Defaults to true
+ *
+ * @type boolean
+ */
+YAHOO.util.DD.prototype.scroll = true;
+
+/**
+ * Sets the pointer offset to the distance between the linked element's top
+ * left corner and the location the element was clicked
+ *
+ * @param {int} iPageX the X coordinate of the click
+ * @param {int} iPageY the Y coordinate of the click
+ */
+YAHOO.util.DD.prototype.autoOffset = function(iPageX, iPageY) {
+    var el = this.getEl();
+    var aCoord = YAHOO.util.Dom.getXY(el);
+    var x = iPageX - aCoord[0];
+    var y = iPageY - aCoord[1];
+    this.setDelta(x, y);
+    this.logger.debug("autoOffset el pos: " + aCoord + ", delta: " + x + "," + y);
+};
+
+/**
+ * Sets the pointer offset.  You can call this directly to force the offset to
+ * be in a particular location (e.g., pass in 0,0 to set it to the center of the
+ * object, as done in ygDDSliderBG)
+ *
+ * @param {int} iDeltaX the distance from the left
+ * @param {int} iDeltaY the distance from the top
+ */
+YAHOO.util.DD.prototype.setDelta = function(iDeltaX, iDeltaY) {
+    this.deltaX = iDeltaX;
+    this.deltaY = iDeltaY;
+    this.logger.debug("deltaX:" + this.deltaX + ", deltaY:" + this.deltaY);
+};
+
+/**
+ * Sets the drag element to the location of the mousedown or click event,
+ * maintaining the cursor location relative to the location on the element
+ * that was clicked.  Override this if you want to place the element in a
+ * location other than where the cursor is.
+ *
+ * @param {int} iPageX the X coordinate of the mousedown or drag event
+ * @param {int} iPageY the Y coordinate of the mousedown or drag event
+ */
+
+YAHOO.util.DD.prototype.setDragElPos = function(iPageX, iPageY) {
+    this.alignElWithMouse(this.getDragEl(), iPageX, iPageY);
+};
+
+/**
+ * Sets the element to the location of the mousedown or click event,
+ * maintaining the cursor location relative to the location on the element
+ * that was clicked.  Override this if you want to place the element in a
+ * location other than where the cursor is.
+ *
+ * @param {HTMLElement} el the element to move
+ * @param {int} iPageX the X coordinate of the mousedown or drag event
+ * @param {int} iPageY the Y coordinate of the mousedown or drag event
+ */
+YAHOO.util.DD.prototype.alignElWithMouse = function(el, iPageX, iPageY) {
+    var oCoord = this.getTargetCoord(iPageX, iPageY);
+    var aCoord = [oCoord.x, oCoord.y];
+    // this.logger.debug("****alignElWithMouse : " + el.id + ", " + aCoord + ", " + el.style.display);
+    YAHOO.util.Dom.setXY(el, aCoord);
+
+    this.cachePosition(oCoord.x, oCoord.y);
+
+    this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
+};
+
+/**
+ * Saves the most recent position so that we can reset the constraints and
+ * tick marks on-demand.  We need to know this so that we can calculate the
+ * number of pixels the element is offset from its original position.
+ */
+YAHOO.util.DD.prototype.cachePosition = function(iPageX, iPageY) {
+    if (iPageX) {
+        this.lastPageX = iPageX;
+        this.lastPageY = iPageY;
+    } else {
+        var aCoord = YAHOO.util.Dom.getXY(this.getEl());
+        this.lastPageX = aCoord[0];
+        this.lastPageY = aCoord[1];
+    }
+};
+
+/**
+ * Auto-scroll the window if the dragged object has been moved beyond the
+ * visible window boundary.
+ *
+ * @param {int} x the drag element's x position
+ * @param {int} y the drag element's y position
+ * @param {int} h the height of the drag element
+ * @param {int} w the width of the drag element
+ * @private
+ */
+YAHOO.util.DD.prototype.autoScroll = function(x, y, h, w) {
+
+    if (this.scroll) {
+        // The client height
+        var clientH = this.DDM.getClientHeight();
+
+        // The client width
+        var clientW = this.DDM.getClientWidth();
+
+        // The amt scrolled down
+        var st = this.DDM.getScrollTop();
+
+        // The amt scrolled right
+        var sl = this.DDM.getScrollLeft();
+
+        // Location of the bottom of the element
+        var bot = h + y;
+
+        // Location of the right of the element
+        var right = w + x;
+
+        // The distance from the cursor to the bottom of the visible area,
+        // adjusted so that we don't scroll if the cursor is beyond the
+        // element drag constraints
+        var toBot = (clientH + st - y - this.deltaY);
+
+        // The distance from the cursor to the right of the visible area
+        var toRight = (clientW + sl - x - this.deltaX);
+
+        // this.logger.debug( " x: " + x + " y: " + y + " h: " + h +
+        // " clientH: " + clientH + " clientW: " + clientW +
+        // " st: " + st + " sl: " + sl + " bot: " + bot +
+        // " right: " + right + " toBot: " + toBot + " toRight: " + toRight);
+
+        // How close to the edge the cursor must be before we scroll
+        // var thresh = (document.all) ? 100 : 40;
+        var thresh = 40;
+
+        // How many pixels to scroll per autoscroll op.  This helps to reduce
+        // clunky scrolling. IE is more sensitive about this ... it needs this
+        // value to be higher.
+        var scrAmt = (document.all) ? 80 : 30;
+
+        // Scroll down if we are near the bottom of the visible page and the
+        // obj extends below the crease
+        if ( bot > clientH && toBot < thresh ) {
+            window.scrollTo(sl, st + scrAmt);
+        }
+
+        // Scroll up if the window is scrolled down and the top of the object
+        // goes above the top border
+        if ( y < st && st > 0 && y - st < thresh ) {
+            window.scrollTo(sl, st - scrAmt);
+        }
+
+        // Scroll right if the obj is beyond the right border and the cursor is
+        // near the border.
+        if ( right > clientW && toRight < thresh ) {
+            window.scrollTo(sl + scrAmt, st);
+        }
+
+        // Scroll left if the window has been scrolled to the right and the obj
+        // extends past the left border
+        if ( x < sl && sl > 0 && x - sl < thresh ) {
+            window.scrollTo(sl - scrAmt, st);
+        }
+    }
+};
+
+/**
+ * Finds the location the element should be placed if we want to move
+ * it to where the mouse location less the click offset would place us.
+ *
+ * @param {int} iPageX the X coordinate of the click
+ * @param {int} iPageY the Y coordinate of the click
+ * @return an object that contains the coordinates (Object.x and Object.y)
+ * @private
+ */
+YAHOO.util.DD.prototype.getTargetCoord = function(iPageX, iPageY) {
+
+    // this.logger.debug("getTargetCoord: " + iPageX + ", " + iPageY);
+
+    var x = iPageX - this.deltaX;
+    var y = iPageY - this.deltaY;
+
+    if (this.constrainX) {
+        if (x < this.minX) { x = this.minX; }
+        if (x > this.maxX) { x = this.maxX; }
+    }
+
+    if (this.constrainY) {
+        if (y < this.minY) { y = this.minY; }
+        if (y > this.maxY) { y = this.maxY; }
+    }
+
+    x = this.getTick(x, this.xTicks);
+    y = this.getTick(y, this.yTicks);
+
+    // this.logger.debug("getTargetCoord " +
+            // " iPageX: " + iPageX +
+            // " iPageY: " + iPageY +
+            // " x: " + x + ", y: " + y);
+
+    return {x:x, y:y};
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DD.prototype.b4MouseDown = function(e) {
+    // this.resetConstraints();
+    this.autoOffset(YAHOO.util.Event.getPageX(e),
+                        YAHOO.util.Event.getPageY(e));
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DD.prototype.b4Drag = function(e) {
+    this.setDragElPos(YAHOO.util.Event.getPageX(e),
+                        YAHOO.util.Event.getPageY(e));
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Debugging ygDragDrop events that can be overridden
+///////////////////////////////////////////////////////////////////////////////
+/*
+YAHOO.util.DD.prototype.startDrag = function(x, y) {
+    this.logger.debug(this.id.toString()  + " startDrag");
+};
+
+YAHOO.util.DD.prototype.onDrag = function(e) {
+    this.logger.debug(this.id.toString() + " onDrag");
+};
+
+YAHOO.util.DD.prototype.onDragEnter = function(e, id) {
+    this.logger.debug(this.id.toString() + " onDragEnter: " + id);
+};
+
+YAHOO.util.DD.prototype.onDragOver = function(e, id) {
+    this.logger.debug(this.id.toString() + " onDragOver: " + id);
+};
+
+YAHOO.util.DD.prototype.onDragOut = function(e, id) {
+    this.logger.debug(this.id.toString() + " onDragOut: " + id);
+};
+
+YAHOO.util.DD.prototype.onDragDrop = function(e, id) {
+    this.logger.debug(this.id.toString() + " onDragDrop: " + id);
+};
+
+YAHOO.util.DD.prototype.endDrag = function(e) {
+    this.logger.debug(this.id.toString() + " endDrag");
+};
+*/
+
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+/**
+ * @class a DragDrop implementation that inserts an empty, bordered div into
+ * the document that follows the cursor during drag operations.  At the time of
+ * the click, the frame div is resized to the dimensions of the linked html
+ * element, and moved to the exact location of the linked element.
+ *
+ * @extends YAHOO.util.DD
+ * @constructor
+ * @param {String} id the id of the linked html element
+ * @param {String} sGroup the group of related DragDrop objects
+ */
+YAHOO.util.DDProxy = function(id, sGroup) {
+    if (id) {
+        this.init(id, sGroup);
+        this.initFrame();
+        this.logger.setModuleName("DDProxy");
+    }
+};
+
+YAHOO.util.DDProxy.prototype = new YAHOO.util.DD();
+
+/**
+ * A reference to the one div element we create for all instances of this class
+ *
+ * @type Object
+ */
+YAHOO.util.DDProxy.frameDiv = null;
+
+/**
+ * the drag frame div id
+ *
+ * @type String
+ */
+YAHOO.util.DDProxy.dragElId = "ygddfdiv";
+
+/**
+ * The border width of the frame.  This is used when we resize the frame to
+ * the size of the linked element.  We substract the border width to make
+ * the div the correct size.
+ *
+ * @TODO find a better way to handle this
+ *
+ * @type int
+ */
+YAHOO.util.DDProxy.prototype.borderWidth = 2;
+
+/**
+ * By default we resize the drag frame to be the same size as the element
+ * we want to drag (this is to get the frame effect).  We can turn it off
+ * if we want a different behavior (ex: ygDDMy2)
+ *
+ * @type boolean
+ */
+YAHOO.util.DDProxy.prototype.resizeFrame = true;
+
+/**
+ * By default the frame is positioned exactly where the drag element is, so
+ * we use the cursor offset provided by YAHOO.util.DD.  Another option that works only if
+ * you do not have constraints on the obj is to have the drag frame centered
+ * around the cursor.  Set centerFrame to true for this effect.  Ex:
+ * ygDDMy2
+ *
+ * @type boolean
+ */
+YAHOO.util.DDProxy.prototype.centerFrame = false;
+
+/**
+ * Create the drag frame if needed
+ */
+YAHOO.util.DDProxy.createFrame = function() {
+    var THIS = YAHOO.util.DDProxy;
+
+    if (!document || !document.body) {
+        setTimeout(THIS.createFrame, 50);
+        return;
+    }
+
+    if (!THIS.frameDiv) {
+        THIS.frameDiv = document.createElement("div");
+        THIS.frameDiv.id = THIS.dragElId;
+        var s = THIS.frameDiv.style;
+        s.position = "absolute";
+        s.visibility = "hidden";
+        s.cursor = "move";
+        s.border = "2px solid #aaa";
+        s.zIndex = 999;
+
+        document.body.appendChild(THIS.frameDiv);
+    }
+};
+
+/**
+ * Initialization for the drag frame element.  Must be called in the
+ * constructor of all subclasses
+ */
+YAHOO.util.DDProxy.prototype.initFrame = function() {
+    YAHOO.util.DDProxy.createFrame();
+    this.setDragElId(YAHOO.util.DDProxy.dragElId);
+    this.useAbsMath = true;
+};
+
+/**
+ * Resizes the drag frame to the dimensions of the clicked object, positions
+ * it over the object, and finally displays it
+ *
+ * @param {int} iPageX X click position
+ * @param {int} iPageY Y click position
+ * @private
+ */
+YAHOO.util.DDProxy.prototype.showFrame = function(iPageX, iPageY) {
+    var el = this.getEl();
+
+    var s = this.getDragEl().style;
+
+    if (this.resizeFrame) {
+        s.width = (parseInt(el.offsetWidth) - (2*this.borderWidth)) + "px";
+        s.height = (parseInt(el.offsetHeight) - (2*this.borderWidth)) + "px";
+    }
+
+    if (this.centerFrame) {
+        this.setDelta(Math.round(parseInt(s.width)/2),
+                Math.round(parseInt(s.width)/2));
+    }
+
+    this.setDragElPos(iPageX, iPageY);
+
+    s.visibility = "";
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DDProxy.prototype.b4MouseDown = function(e) {
+    var x = YAHOO.util.Event.getPageX(e);
+    var y = YAHOO.util.Event.getPageY(e);
+    this.autoOffset(x, y);
+    this.setDragElPos(x, y);
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DDProxy.prototype.b4StartDrag = function(x, y) {
+    // show the drag frame
+    this.logger.debug("start drag show frame, x: " + x + ", y: " + y);
+    this.showFrame(x, y);
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DDProxy.prototype.b4EndDrag = function(e) {
+    this.logger.debug(this.id + " b4EndDrag");
+
+    // hide the drag frame
+    var s = this.getDragEl().style;
+    s.visibility = "hidden";
+};
+
+// overrides YAHOO.util.DragDrop
+// By default we try to move the element to the last location of the frame.
+// This is so that the default behavior mirrors that of YAHOO.util.DD.
+YAHOO.util.DDProxy.prototype.endDrag = function(e) {
+    this.logger.debug(this.id + " endDrag");
+    var lel = this.getEl();
+    var del = this.getDragEl();
+
+    // Show the drag frame briefly so we can get its position
+    del.style.visibility = "";
+
+    // Hide the linked element before the move to get around a Safari
+    // rendering bug.
+    lel.style.visibility = "hidden";
+    YAHOO.util.DDM.moveToEl(lel, del);
+    del.style.visibility = "hidden";
+    lel.style.visibility = "";
+};
+
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+/**
+ * @class a DragDrop implementation that does not move, but can be a drop
+ * target.  You would get the same result by simply omitting implementation
+ * for the event callbacks, but this way we reduce the processing cost of the
+ * event listener and the callbacks.
+ *
+ * @extends YAHOO.util.DragDrop
+ * @constructor
+ * @param {String} id the id of the element that is a drop target
+ * @param {String} sGroup the group of related DragDrop objects
+ */
+
+YAHOO.util.DDTarget = function(id, sGroup) {
+    if (id) {
+        this.initTarget(id, sGroup);
+        this.logger.setModuleName("DDTarget");
+    }
+};
+
+YAHOO.util.DDTarget.prototype = new YAHOO.util.DragDrop();
+
Index: /greenstone3/trunk/web/interfaces/default/js/dragdrop.js
===================================================================
--- /greenstone3/trunk/web/interfaces/default/js/dragdrop.js	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/js/dragdrop.js	(revision 14125)
@@ -0,0 +1,2426 @@
+/*
+Copyright (c) 2006 Yahoo! Inc. All rights reserved.
+version 0.9.0
+*/
+
+/**
+ * @class Defines the interface and base operation of items that that can be
+ * dragged or can be drop targets.  It was designed to be extended, overriding
+ * the event handlers for startDrag, onDrag, onDragOver, onDragOut.
+ * Up to three html elements can be associated with a DragDrop instance:
+ * <ul>
+ * <li>linked element: the element that is passed into the constructor.
+ * This is the element which defines the boundaries for interaction with
+ * other DragDrop objects.</li>
+ * <li>handle element(s): The drag operation only occurs if the element that
+ * was clicked matches a handle element.  By default this is the linked
+ * element, but there are times that you will want only a portion of the
+ * linked element to initiate the drag operation, and the setHandleElId()
+ * method provides a way to define this.</li>
+ * <li>drag element: this represents an the element that would be moved along
+ * with the cursor during a drag operation.  By default, this is the linked
+ * element itself as in {@link YAHOO.util.DD}.  setDragElId() lets you define
+ * a separate element that would be moved, as in {@link YAHOO.util.DDProxy}
+ * </li>
+ * </ul>
+ * This class should not be instantiated until the onload event to ensure that
+ * the associated elements are available.
+ * The following would define a DragDrop obj that would interact with any
+ * other * DragDrop obj in the "group1" group:
+ * <pre>
+ *  dd = new YAHOO.util.DragDrop("div1", "group1");
+ * </pre>
+ * Since none of the event handlers have been implemented, nothing would
+ * actually happen if you were to run the code above.  Normally you would
+ * override this class or one of the default implementations, but you can
+ * also override the methods you want on an instance of the class...
+ * <pre>
+ *  dd.onDragDrop = function(e, id) {
+ *   alert("dd was dropped on " + id);
+ *  }
+ * </pre>
+ * @constructor
+ * @param {String} id of the element that is linked to this instance
+ * @param {String} sGroup the group of related DragDrop objects
+ */
+YAHOO.util.DragDrop = function(id, sGroup) {
+    if (id) {
+        this.init(id, sGroup);
+    }
+};
+
+YAHOO.util.DragDrop.prototype = {
+
+    /**
+     * The id of the element associated with this object.  This is what we
+     * refer to as the "linked element" because the size and position of
+     * this element is used to determine when the drag and drop objects have
+     * interacted.
+     *
+     * @type String
+     */
+    id: null,
+
+    /**
+     * The id of the element that will be dragged.  By default this is same
+     * as the linked element , but could be changed to another element. Ex:
+     * YAHOO.util.DDProxy
+     *
+     * @type String
+     * @private
+     */
+    dragElId: null,
+
+    /**
+     * the id of the element that initiates the drag operation.  By default
+     * this is the linked element, but could be changed to be a child of this
+     * element.  This lets us do things like only starting the drag when the
+     * header element within the linked html element is clicked.
+     *
+     * @type String
+     * @private
+     */
+    handleElId: null,
+
+    /**
+     * An array of HTML tags that will be ignored if clicked.
+     */
+    invalidHandleTypes: null,
+
+    /**
+     * The linked element's absolute X position at the time the drag was
+     * started
+     *
+     * @type int
+     * @private
+     */
+    startPageX: 0,
+
+    /**
+     * The linked element's absolute X position at the time the drag was
+     * started
+     *
+     * @type int
+     * @private
+     */
+    startPageY: 0,
+
+    /**
+     * The group defines a logical collection of DragDrop objects that are
+     * related.  Instances only get events when interacting with other
+     * DragDrop object in the same group.  This lets us define multiple
+     * groups using a single DragDrop subclass if we want.
+     *
+     */
+    groups: null,
+
+    /**
+     * Individual drag/drop instances can be locked.  This will prevent
+     * onmousedown start drag.
+     *
+     * @type boolean
+     * @private
+     */
+    locked: false,
+
+    /**
+     * Lock this instance
+     */
+    lock: function() { this.locked = true; },
+
+    /**
+     * Unlock this instace
+     */
+    unlock: function() { this.locked = false; },
+
+    /**
+     * By default, all insances can be a drop target.  This can be disabled by
+     * setting isTarget to false.
+     *
+     * @type boolean
+     */
+    isTarget: true,
+
+    /**
+     * The padding configured for this drag and drop object for calculating
+     * the drop zone intersection with this object.
+     */
+    padding: null,
+
+    /**
+     * @private
+     */
+    _domRef: null,
+
+    /**
+     * Internal typeof flag
+     * @private
+     */
+    __ygDragDrop: true,
+
+    /**
+     * Set to true when horizontal contraints are applied
+     *
+     * @type boolean
+     * @private
+     */
+    constrainX: false,
+
+    /**
+     * Set to true when vertical contraints are applied
+     *
+     * @type boolean
+     * @private
+     */
+    constrainY: false,
+
+    /**
+     * The left constraint
+     *
+     * @type int
+     * @private
+     */
+    minX: 0,
+
+    /**
+     * The right constraint
+     *
+     * @type int
+     * @private
+     */
+    maxX: 0,
+
+    /**
+     * The up constraint
+     *
+     * @type int
+     * @private
+     */
+    minY: 0,
+
+    /**
+     * The down constraint
+     *
+     * @type int
+     * @private
+     */
+    maxY: 0,
+
+    /**
+     * Maintain offsets when we resetconstraints.  Used to maintain the
+     * slider thumb value, and this needs to be fixed.
+     * @type boolean
+     */
+    maintainOffset: false,
+
+    /**
+     * Array of pixel locations the element will snap to if we specified a
+     * horizontal graduation/interval.  This array is generated automatically
+     * when you define a tick interval.
+     * @type int[]
+     */
+    xTicks: null,
+
+    /**
+     * Array of pixel locations the element will snap to if we specified a
+     * vertical graduation/interval.  This array is generated automatically
+     * when you define a tick interval.
+     * @type int[]
+     */
+    yTicks: null,
+
+    /**
+     * By default the drag and drop instance will only respond to the primary
+     * button click (left button for a right-handed mouse).  Set to true to
+     * allow drag and drop to start with any mouse click that is propogated
+     * by the browser
+     * @type boolean
+     */
+    primaryButtonOnly: true,
+
+    /**
+     * Code that executes immediately before the startDrag event
+     * @private
+     */
+    b4StartDrag: function(x, y) { },
+
+    /**
+     * Abstract method called after a drag/drop object is clicked
+     * and the drag or mousedown time thresholds have beeen met.
+     *
+     * @param {int} X click location
+     * @param {int} Y click location
+     */
+    startDrag: function(x, y) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDrag event
+     * @private
+     */
+    b4Drag: function(e) { },
+
+    /**
+     * Abstract method called during the onMouseMove event while dragging an
+     * object.
+     *
+     * @param {Event} e
+     */
+    onDrag: function(e) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragEnter event
+     * @private
+     */
+    // b4DragEnter: function(e) { },
+
+    /**
+     * Abstract method called when this element fist begins hovering over
+     * another DragDrop obj
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this is hovering over.  In INTERSECT mode, an array of one or more
+     * dragdrop items being hovered over.
+     */
+    onDragEnter: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragOver event
+     * @private
+     */
+    b4DragOver: function(e) { },
+
+    /**
+     * Abstract method called when this element is hovering over another
+     * DragDrop obj
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this is hovering over.  In INTERSECT mode, an array of dd items
+     * being hovered over.
+     */
+    onDragOver: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragOut event
+     * @private
+     */
+    b4DragOut: function(e) { },
+
+    /**
+     * Abstract method called when we are no longer hovering over an element
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this was hovering over.  In INTERSECT mode, an array of dd items
+     * that the mouse is no longer over.
+     */
+    onDragOut: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragDrop event
+     * @private
+     */
+    b4DragDrop: function(e) { },
+
+    /**
+     * Abstract method called when this item is dropped on another DragDrop
+     * obj
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this was dropped on.  In INTERSECT mode, an array of dd items this
+     * was dropped on.
+     */
+    onDragDrop: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the endDrag event
+     * @private
+     */
+    b4EndDrag: function(e) { },
+
+    /**
+     * Fired when we are done dragging the object
+     *
+     * @param {Event} e
+     */
+    endDrag: function(e) { /* override this */ },
+
+    /**
+     * Code executed immediately before the onMouseDown event
+
+     * @param {Event} e
+     * @private
+     */
+    b4MouseDown: function(e) {  },
+
+    /**
+     * Event handler that fires when a drag/drop obj gets a mousedown
+     * @param {Event} e
+     */
+    onMouseDown: function(e) { /* override this */ },
+
+    /**
+     * Event handler that fires when a drag/drop obj gets a mouseup
+     * @param {Event} e
+     */
+    onMouseUp: function(e) { /* override this */ },
+
+    /**
+     * Returns a reference to the linked element
+     *
+     * @return {Object} the html element
+     */
+    getEl: function() {
+        if (!this._domRef) {
+            this._domRef = this.DDM.getElement(this.id);
+        }
+
+        return this._domRef;
+    },
+
+    /**
+     * Returns a reference to the actual element to drag.  By default this is
+     * the same as the html element, but it can be assigned to another
+     * element. An example of this can be found in YAHOO.util.DDProxy
+     *
+     * @return {Object} the html element
+     */
+    getDragEl: function() {
+        return this.DDM.getElement(this.dragElId);
+    },
+
+    /**
+     * Sets up the DragDrop object.  Must be called in the constructor of any
+     * YAHOO.util.DragDrop subclass
+     *
+     * @param id the id of the linked element
+     * @param {String} sGroup the group of related items
+     * element is supposed to be a target only, set to false.
+     */
+    init: function(id, sGroup) {
+        this.initTarget(id, sGroup);
+        YAHOO.util.Event.addListener(id, "mousedown",
+                                          this.handleMouseDown, this, true);
+    },
+
+    /**
+     * Initializes Targeting functionality only... the object does not
+     * get a mousedown handler.
+     *
+     * @param id the id of the linked element
+     * @param {String} sGroup the group of related items
+     * element is supposed to be a target only, set to false.
+     */
+    initTarget: function(id, sGroup) {
+
+        // create a local reference to the drag and drop manager
+        this.DDM = YAHOO.util.DDM;
+
+
+        // set the default padding
+        this.padding = [0, 0, 0, 0];
+
+        // initialize the groups array
+        this.groups = {};
+
+        // set the id
+        this.id = id;
+
+        // the element is a drag handle by default
+        this.setDragElId(id);
+
+        // by default, clicked anchors will not start drag operations
+        this.invalidHandleTypes = {a : "a"};
+
+        // We don't want to register this as the handle with the manager
+        // so we just set the id rather than calling the setter
+        this.handleElId = id;
+
+        // cache the position of the element if we can
+        if (document && document.body) {
+            this.setInitPosition();
+        }
+
+        // add to an interaction group
+        this.addToGroup((sGroup) ? sGroup : "default");
+
+    },
+
+    /**
+     * Configures the padding for the target zone in px.  Effectively expands
+     * (or reduces) the virtual object size for targeting calculations.
+     * Supports css-style shorthand; if only one parameter is passed, all sides
+     * will have that padding, and if only two are passed, the top and bottom
+     * will have the first param, the left and right the second.
+     * @param {int} iTop    Top pad
+     * @param {int} iRight  Right pad
+     * @param {int} iBot    Bot pad
+     * @param {int} iLeft   Left pad
+     */
+    setPadding: function(iTop, iRight, iBot, iLeft) {
+        // this.padding = [iLeft, iRight, iTop, iBot];
+        if (!iRight && 0 !== iRight) {
+            this.padding = [iTop, iTop, iTop, iTop];
+        } else if (!iBot && 0 !== iBot) {
+            this.padding = [iTop, iRight, iTop, iRight];
+        } else {
+            this.padding = [iTop, iRight, iBot, iLeft];
+        }
+    },
+
+    /**
+     * Stores the initial placement of the dd element
+     */
+    setInitPosition: function(diffX, diffY) {
+        var el = this.getEl();
+
+        if (!this.DDM.verifyEl(el)) {
+            return;
+        }
+
+        var dx = diffX || 0;
+        var dy = diffY || 0;
+
+        var p = YAHOO.util.Dom.getXY( el );
+
+        this.initPageX = p[0] - dx;
+        this.initPageY = p[1] - dy;
+
+        this.lastPageX = p[0];
+        this.lastPageY = p[1];
+
+        this.setStartPosition(p);
+    },
+
+    /**
+     * Sets the start position of the element.  This is set when the obj
+     * is initialized, the reset when a drag is started.
+     * @param pos current position (from previous lookup)
+     * @private
+     */
+    setStartPosition: function(pos) {
+
+        var p = pos || YAHOO.util.Dom.getXY( this.getEl() );
+
+        this.startPageX = p[0];
+        this.startPageY = p[1];
+    },
+
+    /**
+     * Add this instance to a group of related drag/drop objects.  All
+     * instances belong to at least one group, and can belong to as many
+     * groups as needed.
+     *
+     * @param sGroup {string} the name of the group
+     */
+    addToGroup: function(sGroup) {
+        this.groups[sGroup] = true;
+        this.DDM.regDragDrop(this, sGroup);
+    },
+
+    /**
+     * Allows you to specify that an element other than the linked element
+     * will be moved with the cursor during a drag
+     *
+     * @param id the id of the element that will be used to initiate the drag
+     */
+    setDragElId: function(id) {
+        this.dragElId = id;
+    },
+
+    /**
+     * Allows you to specify a child of the linked element that should be
+     * used to initiate the drag operation.  An example of this would be if
+     * you have a content div with text and links.  Clicking anywhere in the
+     * content area would normally start the drag operation.  Use this method
+     * to specify that an element inside of the content div is the element
+     * that starts the drag operation.
+     *
+     * @param id the id of the element that will be used to initiate the drag
+     */
+    setHandleElId: function(id) {
+        this.handleElId = id;
+        this.DDM.regHandle(this.id, id);
+    },
+
+    /**
+     * Allows you to set an element outside of the linked element as a drag
+     * handle
+     */
+    setOuterHandleElId: function(id) {
+        YAHOO.util.Event.addListener(id, "mousedown",
+                this.handleMouseDown, this, true);
+        this.setHandleElId(id);
+    },
+
+    /**
+     * Remove all drag and drop hooks for this element
+     */
+    unreg: function() {
+        YAHOO.util.Event.removeListener(this.id, "mousedown",
+                this.handleMouseDown);
+        this._domRef = null;
+        this.DDM._remove(this);
+    },
+
+    /**
+     * Returns true if this instance is locked, or the drag drop mgr is locked
+     * (meaning that all drag/drop is disabled on the page.)
+     *
+     * @return {boolean} true if this obj or all drag/drop is locked, else
+     * false
+     */
+    isLocked: function() {
+        return (this.DDM.isLocked() || this.locked);
+    },
+
+    /**
+     * Fired when this object is clicked
+     *
+     * @param {Event} e
+     * @param {YAHOO.util.DragDrop} oDD the clicked dd object (this dd obj)
+     * @private
+     */
+    handleMouseDown: function(e, oDD) {
+
+
+        var EU = YAHOO.util.Event;
+
+
+        var button = e.which || e.button;
+
+        if (this.primaryButtonOnly && button > 1) {
+            return;
+        }
+
+        if (this.isLocked()) {
+            return;
+        }
+
+
+        this.DDM.refreshCache(this.groups);
+
+        // Only process the event if we really clicked within the linked
+        // element.  The reason we make this check is that in the case that
+        // another element was moved between the clicked element and the
+        // cursor in the time between the mousedown and mouseup events. When
+        // this happens, the element gets the next mousedown event
+        // regardless of where on the screen it happened.
+        var pt = new YAHOO.util.Point(EU.getPageX(e), EU.getPageY(e));
+        if ( this.DDM.isOverTarget(pt, this) )  {
+
+
+            //  check to see if the handle was clicked
+            var srcEl = EU.getTarget(e);
+
+            if (this.isValidHandleChild(srcEl) &&
+                    (this.id == this.handleElId ||
+                     this.DDM.handleWasClicked(srcEl, this.id)) ) {
+
+                // set the initial element position
+                this.setStartPosition();
+
+
+                this.b4MouseDown(e);
+                this.onMouseDown(e);
+                this.DDM.handleMouseDown(e, this);
+
+                this.DDM.stopEvent(e);
+            }
+        }
+    },
+
+    /**
+     * Allows you to specify a tag name that should not start a drag operation
+     * when clicked.  This is designed to facilitate embedding links within a
+     * drag handle that do something other than start the drag.
+     *
+     * @param {string} tagName the type of element to exclude
+     */
+    addInvalidHandleType: function(tagName) {
+        var type = tagName.toUpperCase();
+        this.invalidHandleTypes[type] = type;
+    },
+
+    /**
+     * Unsets an excluded tag name set by addInvalidHandleType
+     *
+     * @param {string} tagName the type of element to unexclude
+     */
+    removeInvalidHandleType: function(tagName) {
+        var type = tagName.toUpperCase();
+        this.invalidHandleTypes[type] = null;
+    },
+
+    /**
+     * Checks the tag exclusion list to see if this click should be ignored
+     *
+     * @param {ygNode} node
+     * @return {boolean} true if this is a valid tag type, false if not
+     */
+    isValidHandleChild: function(node) {
+        var type = node.nodeName;
+
+        if (type == "#text") {
+            type = node.parentNode.nodeName;
+        }
+
+        return (!this.invalidHandleTypes[type]);
+    },
+
+    /**
+     * Create the array of horizontal tick marks if an interval was specified
+     * in setXConstraint().
+     *
+     * @private
+     */
+    setXTicks: function(iStartX, iTickSize) {
+        this.xTicks = [];
+        this.xTickSize = iTickSize;
+
+        var tickMap = {};
+
+        for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
+            if (!tickMap[i]) {
+                this.xTicks[this.xTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
+            if (!tickMap[i]) {
+                this.xTicks[this.xTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        this.xTicks.sort(this.DDM.numericSort) ;
+    },
+
+    /**
+     * Create the array of vertical tick marks if an interval was specified in
+     * setYConstraint().
+     *
+     * @private
+     */
+    setYTicks: function(iStartY, iTickSize) {
+        this.yTicks = [];
+        this.yTickSize = iTickSize;
+
+        var tickMap = {};
+
+        for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
+            if (!tickMap[i]) {
+                this.yTicks[this.yTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
+            if (!tickMap[i]) {
+                this.yTicks[this.yTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        this.yTicks.sort(this.DDM.numericSort) ;
+    },
+
+    /**
+     * By default, the element can be dragged any place on the screen.  Use
+     * this method to limit the horizontal travel of the element.  Pass in
+     * 0,0 for the parameters if you want to lock the drag to the y axis.
+     *
+     * @param {int} iLeft the number of pixels the element can move to the left
+     * @param {int} iRight the number of pixels the element can move to the
+     * right
+     * @param {int} iTickSize optional parameter for specifying that the
+     * element
+     * should move iTickSize pixels at a time.
+     */
+    setXConstraint: function(iLeft, iRight, iTickSize) {
+        this.leftConstraint = iLeft;
+        this.rightConstraint = iRight;
+
+        this.minX = this.initPageX - iLeft;
+        this.maxX = this.initPageX + iRight;
+        if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
+
+        this.constrainX = true;
+    },
+
+    /**
+     * By default, the element can be dragged any place on the screen.  Set
+     * this to limit the vertical travel of the element.  Pass in 0,0 for the
+     * parameters if you want to lock the drag to the x axis.
+     *
+     * @param {int} iUp the number of pixels the element can move up
+     * @param {int} iDown the number of pixels the element can move down
+     * @param {int} iTickSize optional parameter for specifying that the
+     * element should move iTickSize pixels at a time.
+     */
+    setYConstraint: function(iUp, iDown, iTickSize) {
+        this.topConstraint = iUp;
+        this.bottomConstraint = iDown;
+
+        this.minY = this.initPageY - iUp;
+        this.maxY = this.initPageY + iDown;
+        if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
+
+        this.constrainY = true;
+
+    },
+
+    /**
+     * resetConstraints must be called if you manually reposition a dd element.
+     * @param {boolean} maintainOffset
+     */
+    resetConstraints: function() {
+
+
+        // figure out how much this thing has moved
+        var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
+        var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
+
+
+        // reset the initial location
+        this.setInitPosition(dx, dy);
+
+        if (this.constrainX) {
+            this.setXConstraint( this.leftConstraint,
+                                 this.rightConstraint,
+                                 this.xTickSize        );
+        }
+
+        if (this.constrainY) {
+            this.setYConstraint( this.topConstraint,
+                                 this.bottomConstraint,
+                                 this.yTickSize         );
+        }
+    },
+
+    /**
+     * Normally the drag element is moved pixel by pixel, but we can specify
+     * that it move a number of pixels at a time.  This method resolves the
+     * location when we have it set up like this.
+     *
+     * @param {int} val where we want to place the object
+     * @param {int[]} tickArray sorted array of valid points
+     * @return {int} the closest tick
+     * @private
+     */
+    getTick: function(val, tickArray) {
+
+        if (!tickArray) {
+            // If tick interval is not defined, it is effectively 1 pixel,
+            // so we return the value passed to us.
+            return val;
+        } else if (tickArray[0] >= val) {
+            // The value is lower than the first tick, so we return the first
+            // tick.
+            return tickArray[0];
+        } else {
+            for (var i = 0; i < tickArray.length; ++i) {
+                var next = i + 1;
+                if (tickArray[next] && tickArray[next] >= val) {
+                    var diff1 = val - tickArray[i];
+                    var diff2 = tickArray[next] - val;
+                    return (diff2 > diff1) ? tickArray[i] : tickArray[next];
+                }
+            }
+
+            // The value is larger than the last tick, so we return the last
+            // tick.
+            return tickArray[tickArray.length - 1];
+        }
+    },
+
+    /**
+     * toString method
+     * @return {string} string representation of the dd obj
+     */
+    toString: function(val, tickArray) {
+        return ("YAHOO.util.DragDrop {" + this.id + "}");
+    }
+
+};
+
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+// Only load the library once.  Rewriting the manager class would orphan
+// existing drag and drop instances.
+if (!YAHOO.util.DragDropMgr) {
+
+    /**
+     * @class Handles the element interaction for all DragDrop items in the
+     * window.  Generally, you will not call this class directly, but it does
+     * have helper methods that could be useful in your DragDrop
+     * implementations.  This class should not be instantiated; all methods
+     * are are static.
+     *
+     * @constructor
+     */
+    YAHOO.util.DragDropMgr = new function() {
+
+        /**
+         * utility package shorthand
+         * @private
+         */
+        var UTIL = YAHOO.util;
+
+        /**
+         * Two dimensional Array of registered DragDrop objects.  The first
+         * dimension is the DragDrop item group, the second the DragDrop
+         * object.
+         *
+         * @private
+         */
+        this.ids = {};
+
+        /**
+         * Array of element ids defined as drag handles.  Used to determine
+         * if the element that generated the mousedown event is actually the
+         * handle and not the html element itself.
+         *
+         * @private
+         */
+        this.handleIds = {};
+
+        /**
+         * the DragDrop object that is currently being dragged
+         *
+         * @type DragDrop
+         * @private
+         **/
+        this.dragCurrent = null;
+
+        /**
+         * the DragDrop object(s) that are being hovered over
+         *
+         * @type Array
+         * @private
+         */
+        this.dragOvers = {};
+
+        /**
+         * @private
+         */
+
+        /**
+         * the X distance between the cursor and the object being dragged
+         *
+         * @type int
+         * @private
+         */
+        this.deltaX = 0;
+
+        /**
+         * the Y distance between the cursor and the object being dragged
+         *
+         * @type int
+         * @private
+         */
+        this.deltaY = 0;
+
+        /**
+         * Flag to determine if we should prevent the default behavior of the
+         * events we define. By default this is true, but this can be set to
+         * false if you need the default behavior (not recommended)
+         *
+         * @type boolean
+         */
+        this.preventDefault = true;
+
+        /**
+         * Flag to determine if we should stop the propagation of the events
+         * we generate. This is true by default but you may want to set it to
+         * false if the html element contains other features that require the
+         * mouse click.
+         *
+         * @type boolean
+         */
+        this.stopPropagation = true;
+
+        /**
+         * @private
+         */
+        this.initalized = false;
+
+        /**
+         * All drag and drop can be disabled.
+         *
+         * @private
+         */
+        this.locked = false;
+
+        /**
+         * Called the first time an element is registered.
+         *
+         * @private
+         */
+        this.init = function() {
+        };
+
+        /**
+         * In point mode, drag and drop interaction is defined by the
+         * location of the cursor during the drag/drop
+         * @type int
+         */
+        this.POINT     = 0;
+
+        /**
+         * In intersect mode, drag and drop interactio nis defined by the
+         * overlap of two or more drag and drop objects.
+         * @type int
+         */
+        this.INTERSECT = 1;
+
+        /**
+         * The current drag and drop mode.  Default it point mode
+         * @type int
+         */
+        this.mode = this.POINT;
+
+        /**
+         * Runs method on all drag and drop objects
+         * @private
+         */
+        this._execOnAll = function(sMethod, args) {
+            for (var i in this.ids) {
+                for (var j in this.ids[i]) {
+                    var oDD = this.ids[i][j];
+                    if (! this.isTypeOfDD(oDD)) {
+                        continue;
+                    }
+                    oDD[sMethod].apply(oDD, args);
+                }
+            }
+        };
+
+        /**
+         * Drag and drop initialization.  Sets up the global event handlers
+         * @private
+         */
+        this._onLoad = function() {
+
+            this._execOnAll("setInitPosition", []);
+
+
+            var EU = UTIL.Event;
+
+            EU.addListener(document, "mouseup",   this.handleMouseUp, this, true);
+            EU.addListener(document, "mousemove", this.handleMouseMove, this, true);
+            EU.addListener(window,   "unload",    this._onUnload, this, true);
+            EU.addListener(window,   "resize",    this._onResize, this, true);
+            // EU.addListener(window,   "mouseout",    this._test);
+
+            this.initalized = true;
+
+        };
+
+        /**
+         * Reset constraints on all drag and drop objs
+         * @private
+         */
+        this._onResize = function(e) {
+            this._execOnAll("resetConstraints", []);
+        };
+
+        /**
+         * Lock all drag and drop functionality
+         */
+        this.lock = function() { this.locked = true; };
+
+        /**
+         * Unlock all drag and drop functionality
+         */
+        this.unlock = function() { this.locked = false; };
+
+        /**
+         * Is drag and drop locked?
+         *
+         * @return {boolean} True if drag and drop is locked, false otherwise.
+         */
+        this.isLocked = function() { return this.locked; };
+
+        /**
+         * Location cache that is set for all drag drop objects when a drag is
+         * initiated, cleared when the drag is finished.
+         *
+         * @private
+         */
+        this.locationCache = {};
+
+        /**
+         * Set useCache to false if you want to force object the lookup of each
+         * drag and drop linked element constantly during a drag.
+         * @type boolean
+         */
+        this.useCache = true;
+
+        /**
+         * The number of pixels that the mouse needs to move after the
+         * mousedown before the drag is initiated.  Default=3;
+         * @type int
+         */
+        this.clickPixelThresh = 3;
+
+        /**
+         * The number of milliseconds after the mousedown event to initiate the
+         * drag if we don't get a mouseup event. Default=1000
+         * @type int
+         */
+        this.clickTimeThresh = 1000;
+
+        /**
+         * Flag that indicates that either the drag pixel threshold or the
+         * mousdown time threshold has been met
+         * @type boolean
+         * @private
+         */
+        this.dragThreshMet = false;
+
+        /**
+         * Timeout used for the click time threshold
+         * @type Object
+         * @private
+         */
+        this.clickTimeout = null;
+
+        /**
+         * The X position of the mousedown event stored for later use when a
+         * drag threshold is met.
+         * @type int
+         * @private
+         */
+        this.startX = 0;
+
+        /**
+         * The Y position of the mousedown event stored for later use when a
+         * drag threshold is met.
+         * @type int
+         * @private
+         */
+        this.startY = 0;
+
+        /**
+         * Each DragDrop instance must be registered with the DragDropMgr.
+         * This is executed in ygDragDrop.init()
+         *
+         * @param {DragDrop} oDD the DragDrop object to register
+         * @param {String} sGroup the name of the group this element belongs to
+         */
+        this.regDragDrop = function(oDD, sGroup) {
+            if (!this.initialized) { this.init(); }
+
+            if (!this.ids[sGroup]) {
+                this.ids[sGroup] = {};
+            }
+            this.ids[sGroup][oDD.id] = oDD;
+        };
+
+        /**
+         * Unregisters a drag and drop item.  This is executed in
+         * ygDragDrop.unreg, use that method instead of calling this directly.
+         * @private
+         */
+        this._remove = function(oDD) {
+            for (var g in oDD.groups) {
+                if (g && this.ids[g][oDD.id]) {
+                    delete this.ids[g][oDD.id];
+                }
+            }
+            delete this.handleIds[oDD.id];
+        };
+
+        /**
+         * Each DragDrop handle element must be registered.  This is done
+         * automatically when executing ygDragDrop.setHandleElId()
+         *
+         * @param {String} sDDId the DragDrop id this element is a handle for
+         * @param {String} sHandleId the id of the element that is the drag
+         * handle
+         */
+        this.regHandle = function(sDDId, sHandleId) {
+            if (!this.handleIds[sDDId]) {
+                this.handleIds[sDDId] = {};
+            }
+            this.handleIds[sDDId][sHandleId] = sHandleId;
+        };
+
+        /**
+         * Utility function to determine if a given element has been
+         * registered as a drag drop item.
+         *
+         * @param {String} id the element id to check
+         * @return {boolean} true if this element is a DragDrop item,
+         * false otherwise
+         */
+        this.isDragDrop = function(id) {
+            return ( this.getDDById(id) ) ? true : false;
+        };
+
+        /**
+         * Returns the drag and drop instances that are in all groups the
+         * passed in instance belongs to.
+         *
+         * @param {ygDragDrop} p_oDD the obj to get related data for
+         * @param {boolean} bTargetsOnly if true, only return targetable objs
+         * @return {ygDragDrop[]} the related instances
+         */
+        this.getRelated = function(p_oDD, bTargetsOnly) {
+            var oDDs = [];
+            for (var i in p_oDD.groups) {
+                for (j in this.ids[i]) {
+                    var dd = this.ids[i][j];
+                    if (! this.isTypeOfDD(dd)) {
+                        continue;
+                    }
+                    if (!bTargetsOnly || dd.isTarget) {
+                        oDDs[oDDs.length] = dd;
+                    }
+                }
+            }
+
+            return oDDs;
+        };
+
+        /**
+         * Returns true if the specified dd target is a legal target for
+         * the specifice drag obj
+         *
+         * @param {ygDragDrop} the drag obj
+         * @param {ygDragDrop) the target
+         * @return {boolean} true if the target is a legal target for the
+         * dd obj
+         */
+        this.isLegalTarget = function (oDD, oTargetDD) {
+            var targets = this.getRelated(oDD);
+            for (var i =0;i<targets.length;++i) {
+                if (targets[i].id == oTargetDD.id) {
+                    return true;
+                }
+            }
+
+            return false;
+        };
+
+        /**
+         * My goal is to be able to transparently determine if an object is
+         * typeof ygDragDrop, and the exact subclass of ygDragDrop.  typeof
+         * returns "object", oDD.constructor.toString() always returns
+         * "ygDragDrop" and not the name of the subclass.  So for now it just
+         * evaluates a well-known variable in ygDragDrop.
+         *
+         * @param {Object} the object to evaluate
+         * @return {boolean} true if typeof oDD = ygDragDrop
+         */
+        this.isTypeOfDD = function (oDD) {
+            return (oDD && oDD.__ygDragDrop);
+        };
+
+        /**
+         * Utility function to determine if a given element has been
+         * registered as a drag drop handle for the given Drag Drop object.
+         *
+         * @param {String} id the element id to check
+         * @return {boolean} true if this element is a DragDrop handle, false
+         * otherwise
+         */
+        this.isHandle = function(sDDId, sHandleId) {
+            return ( this.handleIds[sDDId] &&
+                            this.handleIds[sDDId][sHandleId] );
+        };
+
+        /**
+         * Returns the DragDrop instance for a given id
+         *
+         * @param {String} id the id of the DragDrop object
+         * @return {DragDrop} the drag drop object, null if it is not found
+         */
+        this.getDDById = function(id) {
+            for (var i in this.ids) {
+                if (this.ids[i][id]) {
+                    return this.ids[i][id];
+                }
+            }
+            return null;
+        };
+
+        /**
+         * Fired after a registered DragDrop object gets the mousedown event.
+         * Sets up the events required to track the object being dragged
+         *
+         * @param {Event} e the event
+         * @param oDD the DragDrop object being dragged
+         * @private
+         */
+        this.handleMouseDown = function(e, oDD) {
+            this.dragCurrent = oDD;
+
+            var el = oDD.getEl();
+
+            // track start position
+            this.startX = UTIL.Event.getPageX(e);
+            this.startY = UTIL.Event.getPageY(e);
+
+            this.deltaX = this.startX - el.offsetLeft;
+            this.deltaY = this.startY - el.offsetTop;
+
+            this.dragThreshMet = false;
+
+            this.clickTimeout = setTimeout(
+               "var DDM=YAHOO.util.DDM;DDM.startDrag(DDM.startX, DDM.startY)",
+               this.clickTimeThresh );
+        };
+
+        /**
+         * Fired when either the drag pixel threshol or the mousedown hold
+         * time threshold has been met.
+         *
+         * @param x {int} the X position of the original mousedown
+         * @param y {int} the Y position of the original mousedown
+         */
+        this.startDrag = function(x, y) {
+            clearTimeout(this.clickTimeout);
+            if (this.dragCurrent) {
+                this.dragCurrent.b4StartDrag(x, y);
+                this.dragCurrent.startDrag(x, y);
+            }
+            this.dragThreshMet = true;
+        };
+
+        /**
+         * Internal function to handle the mouseup event.  Will be invoked
+         * from the context of the document.
+         *
+         * @param {Event} e the event
+         * @private
+         */
+        this.handleMouseUp = function(e) {
+
+            if (! this.dragCurrent) {
+                return;
+            }
+
+            clearTimeout(this.clickTimeout);
+
+            if (this.dragThreshMet) {
+                this.fireEvents(e, true);
+            } else {
+            }
+
+            this.stopDrag(e);
+
+            this.stopEvent(e);
+        };
+
+        /**
+         * Utility to stop event propagation and event default, if these
+         * features are turned on.
+         *
+         * @param {Event} e the event as returned by this.getEvent()
+         */
+        this.stopEvent = function(e) {
+            if (this.stopPropagation) {
+                UTIL.Event.stopPropagation(e);
+            }
+
+            if (this.preventDefault) {
+                UTIL.Event.preventDefault(e);
+            }
+        };
+
+        /**
+         * Internal function to clean up event handlers after the drag
+         * operation is complete
+         *
+         * @param {Event} e the event
+         * @private
+         */
+        this.stopDrag = function(e) {
+
+            // Fire the drag end event for the item that was dragged
+            if (this.dragCurrent) {
+                if (this.dragThreshMet) {
+                    this.dragCurrent.b4EndDrag(e);
+                    this.dragCurrent.endDrag(e);
+                }
+
+                this.dragCurrent.onMouseUp(e);
+            }
+
+            this.dragCurrent = null;
+            this.dragOvers = {};
+        };
+
+        /**
+         * Internal function to handle the mousemove event.  Will be invoked
+         * from the context of the html element.
+         *
+         * @TODO figure out what we can do about mouse events lost when the
+         * user drags objects beyond the window boundary.  Currently we can
+         * detect this in internet explorer by verifying that the mouse is
+         * down during the mousemove event.  Firefox doesn't give us the
+         * button state on the mousemove event.
+         *
+         * @param {Event} e the event
+         * @private
+         */
+        this.handleMouseMove = function(e) {
+            if (! this.dragCurrent) {
+                return;
+            }
+
+            // var button = e.which || e.button;
+
+
+            // check for IE mouseup outside of page boundary
+            if (UTIL.Event.isIE && !e.button) {
+                this.stopEvent(e);
+                return this.handleMouseUp(e);
+            }
+
+            if (!this.dragThreshMet) {
+                var diffX = Math.abs(this.startX - UTIL.Event.getPageX(e));
+                var diffY = Math.abs(this.startY - UTIL.Event.getPageY(e));
+                if (diffX > this.clickPixelThresh ||
+                            diffY > this.clickPixelThresh) {
+                    this.startDrag(this.startX, this.startY);
+                }
+            }
+
+            if (this.dragThreshMet) {
+                this.dragCurrent.b4Drag(e);
+                this.dragCurrent.onDrag(e);
+                this.fireEvents(e, false);
+            }
+
+            this.stopEvent(e);
+        };
+
+        /**
+         * Iterates over all of the DragDrop elements to find ones we are
+         * hovering over or dropping on
+         *
+         * @param {Event} e the event
+         * @param {boolean} isDrop is this a drop op or a mouseover op?
+         * @private
+         */
+        this.fireEvents = function(e, isDrop) {
+            var dc = this.dragCurrent;
+
+            // If the user did the mouse up outside of the window, we could
+            // get here even though we have ended the drag.
+            if (!dc || dc.isLocked()) {
+                return;
+            }
+
+            var x = UTIL.Event.getPageX(e);
+            var y = UTIL.Event.getPageY(e);
+            var pt = new YAHOO.util.Point(x,y);
+
+            // cache the previous dragOver array
+            var oldOvers = [];
+
+            var outEvts   = [];
+            var overEvts  = [];
+            var dropEvts  = [];
+            var enterEvts = [];
+
+            // Check to see if the object we were hovering over is no longer
+            // being hovered over so we can fire the onDragOut event
+            for (var i in this.dragOvers) {
+
+                var ddo = this.dragOvers[i];
+
+                if (! this.isTypeOfDD(ddo)) {
+                    continue;
+                }
+
+                if (! this.isOverTarget(pt, ddo, this.mode)) {
+                    outEvts.push( ddo );
+                }
+
+                oldOvers[i] = true;
+                delete this.dragOvers[i];
+            }
+
+            for (var sGroup in dc.groups) {
+
+                if ("string" != typeof sGroup) {
+                    continue;
+                }
+
+                for (i in this.ids[sGroup]) {
+                    var oDD = this.ids[sGroup][i];
+                    if (! this.isTypeOfDD(oDD)) {
+                        continue;
+                    }
+
+                    if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
+                        if (this.isOverTarget(pt, oDD, this.mode)) {
+                            // look for drop interactions
+                            if (isDrop) {
+                                dropEvts.push( oDD );
+                            // look for drag enter and drag over interactions
+                            } else {
+
+                                // initial drag over: dragEnter fires
+                                if (!oldOvers[oDD.id]) {
+                                    enterEvts.push( oDD );
+                                // subsequent drag overs: dragOver fires
+                                } else {
+                                    overEvts.push( oDD );
+                                }
+
+                                this.dragOvers[oDD.id] = oDD;
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (this.mode) {
+                if (outEvts.length > 0) {
+                    dc.b4DragOut(e, outEvts);
+                    dc.onDragOut(e, outEvts);
+                }
+
+                if (enterEvts.length > 0) {
+                    dc.onDragEnter(e, enterEvts);
+                }
+
+                if (overEvts.length > 0) {
+                    dc.b4DragOver(e, overEvts);
+                    dc.onDragOver(e, overEvts);
+                }
+
+                if (dropEvts.length > 0) {
+                    dc.b4DragDrop(e, dropEvts);
+                    dc.onDragDrop(e, dropEvts);
+                }
+
+            } else {
+                // fire dragout events
+                for (i=0; i < outEvts.length; ++i) {
+                    dc.b4DragOut(e, outEvts[i].id);
+                    dc.onDragOut(e, outEvts[i].id);
+                }
+
+                // fire enter events
+                for (i=0; i < enterEvts.length; ++i) {
+                    // dc.b4DragEnter(e, oDD.id);
+                    dc.onDragEnter(e, enterEvts[i].id);
+                }
+
+                // fire over events
+                for (i=0; i < overEvts.length; ++i) {
+                    dc.b4DragOver(e, overEvts[i].id);
+                    dc.onDragOver(e, overEvts[i].id);
+                }
+
+                // fire drop events
+                for (i=0; i < dropEvts.length; ++i) {
+                    dc.b4DragDrop(e, dropEvts[i].id);
+                    dc.onDragDrop(e, dropEvts[i].id);
+                }
+
+            }
+
+        };
+
+        /**
+         * Helper function for getting the best match from the list of drag
+         * and drop objects returned by the drag and drop events when we are
+         * in INTERSECT mode.  It returns either the first object that the
+         * cursor is over, or the object that has the greatest overlap with
+         * the dragged element.
+         *
+         * @param  {ygDragDrop[]} dds The array of drag and drop objects
+         * targeted
+         * @return {ygDragDrop}       The best single match
+         */
+        this.getBestMatch = function(dds) {
+            var winner = null;
+            // Return null if the input is not what we expect
+            //if (!dds || !dds.length || dds.length == 0) {
+               // winner = null;
+            // If there is only one item, it wins
+            //} else if (dds.length == 1) {
+
+            if (dds.length == 1) {
+                winner = dds[0];
+            } else {
+                // Loop through the targeted items
+                for (var i=0; i<dds.length; ++i) {
+                    var dd = dds[i];
+                    // If the cursor is over the object, it wins.  If the
+                    // cursor is over multiple matches, the first one we come
+                    // to wins.
+                    if (dd.cursorIsOver) {
+                        winner = dd;
+                        break;
+                    // Otherwise the object with the most overlap wins
+                    } else {
+                        if (!winner ||
+                            winner.overlap.getArea() < dd.overlap.getArea()) {
+                            winner = dd;
+                        }
+                    }
+                }
+            }
+
+            return winner;
+        };
+
+        /**
+         * Refreshes the cache of the top-left and bottom-right points of the
+         * drag and drop objects in the specified groups
+         *
+         * @param {Array} aGroups an associative array of groups to refresh
+         */
+        this.refreshCache = function(aGroups) {
+            for (sGroup in aGroups) {
+                if ("string" != typeof sGroup) {
+                    continue;
+                }
+                for (i in this.ids[sGroup]) {
+                    var oDD = this.ids[sGroup][i];
+
+                    if (this.isTypeOfDD(oDD)) {
+                        var loc = this.getLocation(oDD);
+                        if (loc) {
+                            this.locationCache[oDD.id] = loc;
+                        } else {
+                            delete this.locationCache[oDD.id];
+                            // this will unregister the drag and drop object if
+                            // the element is not in a usable state
+                            oDD.unreg();
+                        }
+                    }
+                }
+            }
+        };
+
+        /**
+         * This checks to make sure an element exists and is in the DOM.  The
+         * main purpose is to handle cases where innerHTML is used to remove
+         * drag and drop objects from the DOM.  IE provides an 'unspecified
+         * error' when trying to access the offsetParent of such an element
+         * @param {HTMLElement} el the element to check
+         * @return {boolean} true if the element looks usable
+         */
+        this.verifyEl = function(el) {
+            try {
+                if (el) {
+                    var parent = el.offsetParent;
+                    if (parent) {
+                        return true;
+                    }
+                }
+            } catch(e) {
+            }
+
+            return false;
+        };
+
+        /**
+         * Returns the an array containing the drag and drop element's position
+         * and size, including the ygDragDrop.padding configured for it
+         *
+         * @param {ygDragDrop} oDD the drag and drop object to get the
+         * location for
+         * @return array containing the top left and bottom right points of the
+         * element
+         */
+        this.getLocation = function(oDD) {
+            if (! this.isTypeOfDD(oDD)) {
+                return null;
+            }
+
+            var el = oDD.getEl();
+
+            if (!this.verifyEl(el)) {
+                return null;
+            }
+
+
+            // var aPos = ygPos.getPos(el);
+            var aPos = YAHOO.util.Dom.getXY(el);
+
+            x1 = aPos[0];
+            x2 = x1 + el.offsetWidth;
+
+            y1 = aPos[1];
+            y2 = y1 + el.offsetHeight;
+
+            var t = y1 - oDD.padding[0];
+            var r = x2 + oDD.padding[1];
+            var b = y2 + oDD.padding[2];
+            var l = x1 - oDD.padding[3];
+
+            return new YAHOO.util.Region( t, r, b, l );
+
+        };
+
+        /**
+         * Checks the cursor location to see if it over the target
+         *
+         * @param {YAHOO.util.Point} pt The point to evaluate
+         * @param {ygDragDrop} oDDTarget the DragDrop object we are inspecting
+         * @return {boolean} true if the mouse is over the target
+         * @private
+         */
+        this.isOverTarget = function(pt, oDDTarget, intersect) {
+            // use cache if available
+            var loc = this.locationCache[oDDTarget.id];
+            if (!loc || !this.useCache) {
+                loc = this.getLocation(oDDTarget);
+                this.locationCache[oDDTarget.id] = loc;
+
+            }
+
+
+            // var cursorIsOver =  (x >= loc[3] && x <= loc[1] && y >= loc[0] && y <= loc[2]);
+            //oDDTarget.cursorIsOver = loc.contains( new YAHOO.util.Point(x, y) );
+            oDDTarget.cursorIsOver = loc.contains( pt );
+            oDDTarget.overlap = null;
+
+            // if (this.INTERSECT == this.mode) {
+            if (intersect) {
+
+                var curRegion =
+                    YAHOO.util.Region.getRegion(this.dragCurrent.getDragEl());
+                var overlap = curRegion.intersect(loc);
+
+                if (overlap) {
+                    oDDTarget.overlap = overlap;
+                    return true;
+                } else {
+                    return false;
+                }
+
+            } else {
+                return oDDTarget.cursorIsOver;
+            }
+        };
+
+        /**
+         * @private
+         */
+        this._onUnload = function(e, me) {
+            this.unregAll();
+        };
+
+        /**
+         * Cleans up the drag and drop events and objects.
+         *
+         * @private
+         */
+        this.unregAll = function() {
+
+            if (this.dragCurrent) {
+                this.stopDrag();
+                this.dragCurrent = null;
+            }
+
+            this._execOnAll("unreg", []);
+
+            for (i in this.elementCache) {
+                delete this.elementCache[i];
+            }
+
+            this.elementCache = {};
+            this.ids = {};
+        };
+
+        /**
+         * A cache of DOM elements
+         *
+         * @private
+         */
+        this.elementCache = {};
+
+        /**
+         * Get the wrapper for the DOM element specified
+         *
+         * @param {String} id the id of the elment to get
+         * @return {YAHOO.util.DDM.ElementWrapper} the wrapped element
+         * @private
+         */
+        this.getElWrapper = function(id) {
+            var oWrapper = this.elementCache[id];
+            if (!oWrapper || !oWrapper.el) {
+                oWrapper = this.elementCache[id] =
+                    new this.ElementWrapper(document.getElementById(id));
+            }
+            return oWrapper;
+        };
+
+        /**
+         * Returns the actual DOM element
+         *
+         * @param {String} id the id of the elment to get
+         * @return {Object} The element
+         */
+        this.getElement = function(id) {
+            // return this.getElWrapper(id).el;
+            return document.getElementById(id);
+        };
+
+        /**
+         * Returns the style property for the DOM element (i.e.,
+         * document.getElById(id).style)
+         *
+         * @param {String} id the id of the elment to get
+         * @return {Object} The style property of the element
+         */
+        this.getCss = function(id) {
+            // return this.getElWrapper(id).css;
+            var css = null;
+            var el = document.getElementById(id);
+            if (el) {
+                css = el.style;
+            }
+
+            return css;
+        };
+
+        /**
+         * Inner class for cached elements
+         */
+        this.ElementWrapper = function(el) {
+                /**
+                 * @private
+                 */
+                this.el = el || null;
+                /**
+                 * @private
+                 */
+                this.id = this.el && el.id;
+                /**
+                 * @private
+                 */
+                this.css = this.el && el.style;
+            };
+
+        /**
+         * Returns the X position of an html element
+         * @param el the element for which to get the position
+         * @return {int} the X coordinate
+         */
+        this.getPosX = function(el) {
+            return YAHOO.util.Dom.getX(el);
+        };
+
+        /**
+         * Returns the Y position of an html element
+         * @param el the element for which to get the position
+         * @return {int} the Y coordinate
+         */
+        this.getPosY = function(el) {
+            return YAHOO.util.Dom.getY(el);
+        };
+
+        /**
+         * Swap two nodes.  In IE, we use the native method, for others we
+         * emulate the IE behavior
+         *
+         * @param n1 the first node to swap
+         * @param n2 the other node to swap
+         */
+        this.swapNode = function(n1, n2) {
+            if (n1.swapNode) {
+                n1.swapNode(n2);
+            } else {
+                // the node reference order for the swap is a little tricky.
+                var p = n2.parentNode;
+                var s = n2.nextSibling;
+                n1.parentNode.replaceChild(n2,n1);
+                p.insertBefore(n1,s);
+            }
+        };
+
+        /**
+         * @private
+         */
+        this.getScroll = function () {
+            var t, l;
+            if (document.documentElement && document.documentElement.scrollTop) {
+                t = document.documentElement.scrollTop;
+                l = document.documentElement.scrollLeft;
+            } else if (document.body) {
+                t = document.body.scrollTop;
+                l = document.body.scrollLeft;
+            }
+            return { top: t, left: l };
+        };
+
+        /**
+         * Returns the specified element style property
+         * @param {HTMLElement} el          the element
+         * @param {string}      styleProp   the style property
+         * @return {string}     The value of the style property
+         */
+        this.getStyle = function(el, styleProp) {
+            if (el.style.styleProp) {
+                return el.style.styleProp;
+            } else if (el.currentStyle) {
+                return el.currentStyle[styleProp];
+            } else if (document.defaultView) {
+                return document.defaultView.getComputedStyle(el, null).
+                    getPropertyValue(styleProp);
+            }
+        };
+
+        /**
+         * Gets the scrollTop
+         *
+         * @return {int} the document's scrollTop
+         */
+        this.getScrollTop = function () { return this.getScroll().top; };
+
+        /**
+         * Gets the scrollLeft
+         *
+         * @return {int} the document's scrollTop
+         */
+        this.getScrollLeft = function () { return this.getScroll().left; };
+
+        this.moveToEl = function (moveEl, targetEl) {
+            var aCoord = YAHOO.util.Dom.getXY(targetEl);
+            YAHOO.util.Dom.setXY(moveEl, aCoord);
+        };
+
+        /**
+         * Gets the client height
+         *
+         * @return {int} client height in px
+         */
+        this.getClientHeight = function() {
+            return (window.innerHeight) ? window.innerHeight :
+                (document.documentElement && document.documentElement.clientHeight) ?
+                document.documentElement.clientHeight : document.body.offsetHeight;
+        };
+
+        /**
+         * Gets the client width
+         *
+         * @return {int} client width in px
+         */
+        this.getClientWidth = function() {
+            return (window.innerWidth) ? window.innerWidth :
+                (document.documentElement && document.documentElement.clientWidth) ?
+                document.documentElement.clientWidth : document.body.offsetWidth;
+        };
+
+        /**
+         * numeric array sort function
+         */
+        this.numericSort = function(a, b) { return (a - b); };
+
+        /**
+         * @private
+         */
+        this._timeoutCount = 0;
+
+        /**
+         * @private
+         * Trying to make the load order less important.  Without this we get
+         * an error if this file is loaded before the Event Utility.
+         */
+        this._addListeners = function() {
+            if ( UTIL.Event &&
+                 document          &&
+                 document.body        ) {
+
+                this._onLoad();
+            } else {
+                if (this._timeoutCount > 500) {
+                } else {
+                    setTimeout("YAHOO.util.DDM._addListeners()", 10);
+                    this._timeoutCount += 1;
+                }
+            }
+
+        };
+
+        /**
+         * Recursively searches the immediate parent and all child nodes for
+         * the handle element in order to determine wheter or not it was
+         * clicked.
+         *
+         * @param node the html element to inspect
+         */
+        this.handleWasClicked = function(node, id) {
+            if (this.isHandle(id, node.id)) {
+                return true;
+            } else {
+                // check to see if this is a text node child of the one we want
+                var p = node.parentNode;
+
+                while (p) {
+                    if (this.isHandle(id, p.id)) {
+                        return true;
+                    } else {
+                        p = p.parentNode;
+                    }
+                }
+            }
+
+            return false;
+        };
+
+    };
+
+    // shorter alias, save a few bytes
+    YAHOO.util.DDM = YAHOO.util.DragDropMgr;
+    YAHOO.util.DDM._addListeners();
+
+}
+
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+/**
+ * @class a DragDrop implementation where the linked element follows the
+ * mouse cursor.
+ *
+ * @extends DragDrop
+ * @constructor
+ * @param {String} id the id of the linked element
+ * @param {String} sGroup the group of related DragDrop items
+ */
+YAHOO.util.DD = function(id, sGroup) {
+    if (id) {
+        this.init(id, sGroup);
+    }
+};
+
+YAHOO.util.DD.prototype = new YAHOO.util.DragDrop();
+
+/**
+ * Should we auto-scroll? Defaults to true
+ *
+ * @type boolean
+ */
+YAHOO.util.DD.prototype.scroll = true;
+
+/**
+ * Sets the pointer offset to the distance between the linked element's top
+ * left corner and the location the element was clicked
+ *
+ * @param {int} iPageX the X coordinate of the click
+ * @param {int} iPageY the Y coordinate of the click
+ */
+YAHOO.util.DD.prototype.autoOffset = function(iPageX, iPageY) {
+    var el = this.getEl();
+    var aCoord = YAHOO.util.Dom.getXY(el);
+    var x = iPageX - aCoord[0];
+    var y = iPageY - aCoord[1];
+    this.setDelta(x, y);
+};
+
+/**
+ * Sets the pointer offset.  You can call this directly to force the offset to
+ * be in a particular location (e.g., pass in 0,0 to set it to the center of the
+ * object, as done in ygDDSliderBG)
+ *
+ * @param {int} iDeltaX the distance from the left
+ * @param {int} iDeltaY the distance from the top
+ */
+YAHOO.util.DD.prototype.setDelta = function(iDeltaX, iDeltaY) {
+    this.deltaX = iDeltaX;
+    this.deltaY = iDeltaY;
+};
+
+/**
+ * Sets the drag element to the location of the mousedown or click event,
+ * maintaining the cursor location relative to the location on the element
+ * that was clicked.  Override this if you want to place the element in a
+ * location other than where the cursor is.
+ *
+ * @param {int} iPageX the X coordinate of the mousedown or drag event
+ * @param {int} iPageY the Y coordinate of the mousedown or drag event
+ */
+
+YAHOO.util.DD.prototype.setDragElPos = function(iPageX, iPageY) {
+    this.alignElWithMouse(this.getDragEl(), iPageX, iPageY);
+};
+
+/**
+ * Sets the element to the location of the mousedown or click event,
+ * maintaining the cursor location relative to the location on the element
+ * that was clicked.  Override this if you want to place the element in a
+ * location other than where the cursor is.
+ *
+ * @param {HTMLElement} el the element to move
+ * @param {int} iPageX the X coordinate of the mousedown or drag event
+ * @param {int} iPageY the Y coordinate of the mousedown or drag event
+ */
+YAHOO.util.DD.prototype.alignElWithMouse = function(el, iPageX, iPageY) {
+    var oCoord = this.getTargetCoord(iPageX, iPageY);
+    var aCoord = [oCoord.x, oCoord.y];
+    YAHOO.util.Dom.setXY(el, aCoord);
+
+    this.cachePosition(oCoord.x, oCoord.y);
+
+    this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
+};
+
+/**
+ * Saves the most recent position so that we can reset the constraints and
+ * tick marks on-demand.  We need to know this so that we can calculate the
+ * number of pixels the element is offset from its original position.
+ */
+YAHOO.util.DD.prototype.cachePosition = function(iPageX, iPageY) {
+    if (iPageX) {
+        this.lastPageX = iPageX;
+        this.lastPageY = iPageY;
+    } else {
+        var aCoord = YAHOO.util.Dom.getXY(this.getEl());
+        this.lastPageX = aCoord[0];
+        this.lastPageY = aCoord[1];
+    }
+};
+
+/**
+ * Auto-scroll the window if the dragged object has been moved beyond the
+ * visible window boundary.
+ *
+ * @param {int} x the drag element's x position
+ * @param {int} y the drag element's y position
+ * @param {int} h the height of the drag element
+ * @param {int} w the width of the drag element
+ * @private
+ */
+YAHOO.util.DD.prototype.autoScroll = function(x, y, h, w) {
+
+    if (this.scroll) {
+        // The client height
+        var clientH = this.DDM.getClientHeight();
+
+        // The client width
+        var clientW = this.DDM.getClientWidth();
+
+        // The amt scrolled down
+        var st = this.DDM.getScrollTop();
+
+        // The amt scrolled right
+        var sl = this.DDM.getScrollLeft();
+
+        // Location of the bottom of the element
+        var bot = h + y;
+
+        // Location of the right of the element
+        var right = w + x;
+
+        // The distance from the cursor to the bottom of the visible area,
+        // adjusted so that we don't scroll if the cursor is beyond the
+        // element drag constraints
+        var toBot = (clientH + st - y - this.deltaY);
+
+        // The distance from the cursor to the right of the visible area
+        var toRight = (clientW + sl - x - this.deltaX);
+
+
+        // How close to the edge the cursor must be before we scroll
+        // var thresh = (document.all) ? 100 : 40;
+        var thresh = 40;
+
+        // How many pixels to scroll per autoscroll op.  This helps to reduce
+        // clunky scrolling. IE is more sensitive about this ... it needs this
+        // value to be higher.
+        var scrAmt = (document.all) ? 80 : 30;
+
+        // Scroll down if we are near the bottom of the visible page and the
+        // obj extends below the crease
+        if ( bot > clientH && toBot < thresh ) {
+            window.scrollTo(sl, st + scrAmt);
+        }
+
+        // Scroll up if the window is scrolled down and the top of the object
+        // goes above the top border
+        if ( y < st && st > 0 && y - st < thresh ) {
+            window.scrollTo(sl, st - scrAmt);
+        }
+
+        // Scroll right if the obj is beyond the right border and the cursor is
+        // near the border.
+        if ( right > clientW && toRight < thresh ) {
+            window.scrollTo(sl + scrAmt, st);
+        }
+
+        // Scroll left if the window has been scrolled to the right and the obj
+        // extends past the left border
+        if ( x < sl && sl > 0 && x - sl < thresh ) {
+            window.scrollTo(sl - scrAmt, st);
+        }
+    }
+};
+
+/**
+ * Finds the location the element should be placed if we want to move
+ * it to where the mouse location less the click offset would place us.
+ *
+ * @param {int} iPageX the X coordinate of the click
+ * @param {int} iPageY the Y coordinate of the click
+ * @return an object that contains the coordinates (Object.x and Object.y)
+ * @private
+ */
+YAHOO.util.DD.prototype.getTargetCoord = function(iPageX, iPageY) {
+
+
+    var x = iPageX - this.deltaX;
+    var y = iPageY - this.deltaY;
+
+    if (this.constrainX) {
+        if (x < this.minX) { x = this.minX; }
+        if (x > this.maxX) { x = this.maxX; }
+    }
+
+    if (this.constrainY) {
+        if (y < this.minY) { y = this.minY; }
+        if (y > this.maxY) { y = this.maxY; }
+    }
+
+    x = this.getTick(x, this.xTicks);
+    y = this.getTick(y, this.yTicks);
+
+
+    return {x:x, y:y};
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DD.prototype.b4MouseDown = function(e) {
+    // this.resetConstraints();
+    this.autoOffset(YAHOO.util.Event.getPageX(e),
+                        YAHOO.util.Event.getPageY(e));
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DD.prototype.b4Drag = function(e) {
+    this.setDragElPos(YAHOO.util.Event.getPageX(e),
+                        YAHOO.util.Event.getPageY(e));
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Debugging ygDragDrop events that can be overridden
+///////////////////////////////////////////////////////////////////////////////
+/*
+YAHOO.util.DD.prototype.startDrag = function(x, y) {
+};
+
+YAHOO.util.DD.prototype.onDrag = function(e) {
+};
+
+YAHOO.util.DD.prototype.onDragEnter = function(e, id) {
+};
+
+YAHOO.util.DD.prototype.onDragOver = function(e, id) {
+};
+
+YAHOO.util.DD.prototype.onDragOut = function(e, id) {
+};
+
+YAHOO.util.DD.prototype.onDragDrop = function(e, id) {
+};
+
+YAHOO.util.DD.prototype.endDrag = function(e) {
+};
+*/
+
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+/**
+ * @class a DragDrop implementation that inserts an empty, bordered div into
+ * the document that follows the cursor during drag operations.  At the time of
+ * the click, the frame div is resized to the dimensions of the linked html
+ * element, and moved to the exact location of the linked element.
+ *
+ * @extends YAHOO.util.DD
+ * @constructor
+ * @param {String} id the id of the linked html element
+ * @param {String} sGroup the group of related DragDrop objects
+ */
+YAHOO.util.DDProxy = function(id, sGroup) {
+    if (id) {
+        this.init(id, sGroup);
+        this.initFrame();
+    }
+};
+
+YAHOO.util.DDProxy.prototype = new YAHOO.util.DD();
+
+/**
+ * A reference to the one div element we create for all instances of this class
+ *
+ * @type Object
+ */
+YAHOO.util.DDProxy.frameDiv = null;
+
+/**
+ * the drag frame div id
+ *
+ * @type String
+ */
+YAHOO.util.DDProxy.dragElId = "ygddfdiv";
+
+/**
+ * The border width of the frame.  This is used when we resize the frame to
+ * the size of the linked element.  We substract the border width to make
+ * the div the correct size.
+ *
+ * @TODO find a better way to handle this
+ *
+ * @type int
+ */
+YAHOO.util.DDProxy.prototype.borderWidth = 2;
+
+/**
+ * By default we resize the drag frame to be the same size as the element
+ * we want to drag (this is to get the frame effect).  We can turn it off
+ * if we want a different behavior (ex: ygDDMy2)
+ *
+ * @type boolean
+ */
+YAHOO.util.DDProxy.prototype.resizeFrame = true;
+
+/**
+ * By default the frame is positioned exactly where the drag element is, so
+ * we use the cursor offset provided by YAHOO.util.DD.  Another option that works only if
+ * you do not have constraints on the obj is to have the drag frame centered
+ * around the cursor.  Set centerFrame to true for this effect.  Ex:
+ * ygDDMy2
+ *
+ * @type boolean
+ */
+YAHOO.util.DDProxy.prototype.centerFrame = false;
+
+/**
+ * Create the drag frame if needed
+ */
+YAHOO.util.DDProxy.createFrame = function() {
+    var THIS = YAHOO.util.DDProxy;
+
+    if (!document || !document.body) {
+        setTimeout(THIS.createFrame, 50);
+        return;
+    }
+
+    if (!THIS.frameDiv) {
+        THIS.frameDiv = document.createElement("div");
+        THIS.frameDiv.id = THIS.dragElId;
+        var s = THIS.frameDiv.style;
+        s.position = "absolute";
+        s.visibility = "hidden";
+        s.cursor = "move";
+        s.border = "2px solid #aaa";
+        s.zIndex = 999;
+
+        document.body.appendChild(THIS.frameDiv);
+    }
+};
+
+/**
+ * Initialization for the drag frame element.  Must be called in the
+ * constructor of all subclasses
+ */
+YAHOO.util.DDProxy.prototype.initFrame = function() {
+    YAHOO.util.DDProxy.createFrame();
+    this.setDragElId(YAHOO.util.DDProxy.dragElId);
+    this.useAbsMath = true;
+};
+
+/**
+ * Resizes the drag frame to the dimensions of the clicked object, positions
+ * it over the object, and finally displays it
+ *
+ * @param {int} iPageX X click position
+ * @param {int} iPageY Y click position
+ * @private
+ */
+YAHOO.util.DDProxy.prototype.showFrame = function(iPageX, iPageY) {
+    var el = this.getEl();
+
+    var s = this.getDragEl().style;
+
+    if (this.resizeFrame) {
+        s.width = (parseInt(el.offsetWidth) - (2*this.borderWidth)) + "px";
+        s.height = (parseInt(el.offsetHeight) - (2*this.borderWidth)) + "px";
+    }
+
+    if (this.centerFrame) {
+        this.setDelta(Math.round(parseInt(s.width)/2),
+                Math.round(parseInt(s.width)/2));
+    }
+
+    this.setDragElPos(iPageX, iPageY);
+
+    s.visibility = "";
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DDProxy.prototype.b4MouseDown = function(e) {
+    var x = YAHOO.util.Event.getPageX(e);
+    var y = YAHOO.util.Event.getPageY(e);
+    this.autoOffset(x, y);
+    this.setDragElPos(x, y);
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DDProxy.prototype.b4StartDrag = function(x, y) {
+    // show the drag frame
+    this.showFrame(x, y);
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DDProxy.prototype.b4EndDrag = function(e) {
+
+    // hide the drag frame
+    var s = this.getDragEl().style;
+    s.visibility = "hidden";
+};
+
+// overrides YAHOO.util.DragDrop
+// By default we try to move the element to the last location of the frame.
+// This is so that the default behavior mirrors that of YAHOO.util.DD.
+YAHOO.util.DDProxy.prototype.endDrag = function(e) {
+    var lel = this.getEl();
+    var del = this.getDragEl();
+
+    // Show the drag frame briefly so we can get its position
+    del.style.visibility = "";
+
+    // Hide the linked element before the move to get around a Safari
+    // rendering bug.
+    lel.style.visibility = "hidden";
+    YAHOO.util.DDM.moveToEl(lel, del);
+    del.style.visibility = "hidden";
+    lel.style.visibility = "";
+};
+
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+/**
+ * @class a DragDrop implementation that does not move, but can be a drop
+ * target.  You would get the same result by simply omitting implementation
+ * for the event callbacks, but this way we reduce the processing cost of the
+ * event listener and the callbacks.
+ *
+ * @extends YAHOO.util.DragDrop
+ * @constructor
+ * @param {String} id the id of the element that is a drop target
+ * @param {String} sGroup the group of related DragDrop objects
+ */
+
+YAHOO.util.DDTarget = function(id, sGroup) {
+    if (id) {
+        this.initTarget(id, sGroup);
+    }
+};
+
+YAHOO.util.DDTarget.prototype = new YAHOO.util.DragDrop();
+
Index: /greenstone3/trunk/web/interfaces/default/js/event.js
===================================================================
--- /greenstone3/trunk/web/interfaces/default/js/event.js	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/js/event.js	(revision 14125)
@@ -0,0 +1,901 @@
+/*
+Copyright (c) 2006 Yahoo! Inc. All rights reserved.
+version 0.9.0
+*/
+
+/**
+ * @class The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ * @param {String} type The type of event, which is passed to the callback
+ *                 when the event fires
+ * @param {Object} oScope The context the event will fire from.  "this" will
+ *                 refer to this object in the callback.  Default value:
+ *                 the window object.  The listener can override this.
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope) {
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from.  Defaults to the window obj
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * The subscribers to this event
+     * @type array
+     */
+    this.subscribers = [];
+
+    // Register with the event utility for automatic cleanup.  Made optional
+    // so that CustomEvent can be used independently of pe.event
+    if (YAHOO.util["Event"]) {
+        YAHOO.util.Event.regCE(this);
+    }
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0; i<this.subscribers.length; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     *
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        for (var i=0; i<this.subscribers.length; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, arguments, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     */
+    unsubscribeAll: function() {
+        for (var i=0; i<this.subscribers.length; ++i) {
+            this._delete(i);
+        }
+    },
+
+    /**
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        delete this.subscribers[index];
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * @class
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+    /**
+     * The callback that will be execute when the event fires
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+// Only load this library once.  If it is loaded a second time, existing
+// events cannot be detached.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @class
+ * @constructor
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of the custom events that have been defined.  Used for
+         * automatic cleanup
+         * @type array
+         * @private
+         */
+        var customEvents = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @private
+         */
+        var legacyHandlers = [];
+
+        return { // PREPROCESS
+
+            /**
+             * Element to bind, int constant
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @private
+             */
+            isSafari: (navigator.userAgent.match(/safari/gi)),
+
+            /**
+             * @private
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             */
+            isIE: (!this.isSafari && navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * Appends an event handler
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0; i< el.length; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete) {
+                        el = this.getEl(el);
+                    } else {
+                        // defer adding the event until onload fires
+                        delayedListeners[delayedListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    if (legacyIndex == -1) {
+
+                        legacyIndex = legacyEvents.length;
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    legacyHandlers[legacyIndex].push(index);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // Internet Explorer abstraction
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * Shorthand for YAHOO.util.Event.addListener
+             * @type function
+             */
+            // on: this.addListener,
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // alert("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                // var el = legacyEvents[YAHOO.util.Event.EL];
+
+                /* this is not working because the property may get populated
+                // fire the event we replaced, if it exists
+                var origHandler = legacyEvents[2];
+                alert(origHandler);
+                if (origHandler && origHandler.call) {
+                    var ret = origHandler.call(el, e);
+                    ok = (ret);
+                }
+                */
+
+                var le = legacyHandlers[legacyIndex];
+                for (i=0; i < le.length; ++i) {
+                    var index = le[i];
+                    // alert(index);
+                    if (index) {
+                        var li = listeners[index];
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                        // alert(ok);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                for (var i=0; i < legacyEvents.length; ++i) {
+                    var le = legacyEvents[i];
+                    if (le && le[0] == el && le[1] == sType) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+
+                return ( (!el.addEventListener && !el.attachEvent) ||
+                                (sType == "click" && this.isSafari) );
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn) {
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0; i< el.length; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                var cacheItem = null;
+                var index = this._getCacheIndex(el, sType, fn);
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // alert("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                delete listeners[index];
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+
+                if (resolveTextNode && t && "#text" == t.nodeName) {
+                    return t.parentNode;
+                } else {
+                    return t;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the event's related target
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return t;
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Returns the event, should not be necessary for user to call
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || (ev.type == "keypress") ? ev.keyCode : 0;
+            },
+
+            /**
+             * @private
+             * Locating the saved event handler data by function ref
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0; i< listeners.length; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             */
+            _isValidCollection: function(o) {
+                // alert(o.constructor.toString())
+                // alert(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @private
+             */
+            getEl: function(id) {
+                /*
+                // this is a problem when replaced via document.getElementById
+                if (! this.elCache[id]) {
+                    try {
+                        var el = document.getElementById(id);
+                        if (el) {
+                            this.elCache[id] = el;
+                        }
+                    } catch (er) {
+                    }
+                }
+                return this.elCache[id];
+                */
+
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             */
+            clearCache: function() {
+                for (i in this.elCache) {
+                    delete this.elCache[i];
+                }
+            },
+
+            /**
+             * Called by CustomEvent instances to provide a handle to the
+             * event * that can be removed later on.  Should be package
+             * protected.
+             * @private
+             */
+            regCE: function(ce) {
+                customEvents.push(ce);
+            },
+
+            /**
+             * @private
+             * hook up any deferred listeners
+             */
+            _load: function(e) {
+                loadComplete = true;
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting * to attach to DOM Nodes as soon as they are
+             * available
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+
+                for (var i=0; i < delayedListeners.length; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        }
+                    }
+                }
+
+                if (tryAgain) {
+                    setTimeout("YAHOO.util.Event._tryPreloadAttach()", 50);
+                }
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             */
+            _unload: function(e, me) {
+                for (var i=0; i < unloadListeners.length; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[this.ADJ_SCOPE]) ? l[this.SCOPE]: window;
+                        l[this.FN].call(scope, this.getEvent(e), l[this.SCOPE] );
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    for (i = 0; i < listeners.length; ++i) {
+                        l = listeners[i];
+                        if (l) {
+                            this.removeListener(l[this.EL], l[this.TYPE],
+                                    l[this.FN]);
+                        }
+                    }
+
+                    this.clearCache();
+                }
+
+                for (i = 0; i < customEvents.length; ++i) {
+                    customEvents[i].unsubscribeAll();
+                    delete customEvents[i];
+                }
+
+                for (i = 0; i < legacyEvents.length; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+            },
+
+            /**
+             * Returns scrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement; db = document.body;
+                if (dd && dd.scrollTop) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            }
+        };
+    } ();
+
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event.on(window, "load", YAHOO.util.Event._load,
+                YAHOO.util.Event, true);
+    }
+
+    YAHOO.util.Event.on(window, "unload", YAHOO.util.Event._unload,
+                YAHOO.util.Event, true);
+
+    YAHOO.util.Event._tryPreloadAttach();
+
+}
+
Index: /greenstone3/trunk/web/interfaces/default/js/key.js
===================================================================
--- /greenstone3/trunk/web/interfaces/default/js/key.js	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/js/key.js	(revision 14125)
@@ -0,0 +1,34 @@
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+YAHOO.util.Key = new function() {
+	// this.logger	= new ygLogger("ygEventUtil");
+	// DOM key constants 
+	this.DOM_VK_UNDEFINED               = 0x0;
+	this.DOM_VK_RIGHT_ALT               = 0x12;
+	this.DOM_VK_LEFT_ALT                = 0x12;
+	this.DOM_VK_LEFT_CONTROL            = 0x11;
+	this.DOM_VK_RIGHT_CONTROL           = 0x11;
+	this.DOM_VK_LEFT_SHIFT              = 0x10;
+	this.DOM_VK_RIGHT_SHIFT             = 0x10;
+	this.DOM_VK_META                    = 0x9D;
+	this.DOM_VK_BACK_SPACE              = 0x08;
+	this.DOM_VK_CAPS_LOCK               = 0x14;
+	this.DOM_VK_DELETE                  = 0x7F;
+	this.DOM_VK_END                     = 0x23;
+	this.DOM_VK_ENTER                   = 0x0D;
+	this.DOM_VK_ESCAPE                  = 0x1B;
+	this.DOM_VK_HOME                    = 0x24;
+	this.DOM_VK_NUM_LOCK                = 0x90;
+	this.DOM_VK_PAUSE                   = 0x13;
+	this.DOM_VK_PRINTSCREEN             = 0x9A;
+	this.DOM_VK_SCROLL_LOCK             = 0x91;
+	this.DOM_VK_SPACE                   = 0x20;
+	this.DOM_VK_TAB                     = 0x09;
+	this.DOM_VK_LEFT                    = 0x25;
+	this.DOM_VK_RIGHT                   = 0x27;
+	this.DOM_VK_UP                      = 0x26;
+	this.DOM_VK_DOWN                    = 0x28;
+	this.DOM_VK_PAGE_DOWN               = 0x22;
+	this.DOM_VK_PAGE_UP                 = 0x21;
+};
+
Index: /greenstone3/trunk/web/interfaces/default/js/ygDDOnTop.js
===================================================================
--- /greenstone3/trunk/web/interfaces/default/js/ygDDOnTop.js	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/js/ygDDOnTop.js	(revision 14125)
@@ -0,0 +1,46 @@
+
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+/**
+ * @class a DragDrop implementation that moves the object as it is being dragged,
+ * and keeps the object being dragged on top.  This is a subclass of ygDD rather
+ * than DragDrop, and inherits the implementation of most of the event listeners
+ * from that class.
+ *
+ * @extends ygDD
+ * @constructor
+ * @param {String} id the id of the linked element
+ * @param {String} sGroup the group of related DragDrop items
+ */
+function ygDDOnTop(id, sGroup) {
+	if (id) {
+		this.init(id, sGroup);
+	
+	}
+}
+
+ygDDOnTop.prototype = new YAHOO.util.DD();
+
+/**
+ * The inital z-index of the element, stored so we can restore it later
+ *
+ * @type int
+ */
+ygDDOnTop.prototype.origZ = 0;
+
+ygDDOnTop.prototype.startDrag = function(x, y) {
+
+	var style = this.getEl().style;
+
+	// store the original z-index
+	this.origZ = style.zIndex;
+
+	// The z-index needs to be set very high so the element will indeed be on top
+	style.zIndex = 999;
+}
+
+ygDDOnTop.prototype.endDrag = function(e) {
+
+	// restore the original z-index
+	this.getEl().style.zIndex = this.origZ;
+};
Index: /greenstone3/trunk/web/interfaces/default/js/ygDDPlayer.js
===================================================================
--- /greenstone3/trunk/web/interfaces/default/js/ygDDPlayer.js	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/js/ygDDPlayer.js	(revision 14125)
@@ -0,0 +1,350 @@
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+function ygDDStack(id, sGroup) {
+	if (id) {
+		this.init(id, sGroup);
+		this.initFrame();
+	}
+}
+
+ygDDStack.prototype = new YAHOO.util.DDTarget();
+
+ygDDPlayer.TYPE = "ygDDPlayer";
+
+/**
+ * @class a YAHOO.util.DDFramed implementation. During the drag over event, the
+ * dragged element is inserted before the dragged-over element.
+ *
+ * @extends YAHOO.util.DDProxy
+ * @constructor
+ * @param {String} id the id of the linked element
+ * @param {String} sGroup the group of related DragDrop objects
+ */
+function ygDDPlayer(id, sGroup,bl) {
+    this.initPlayer(id, sGroup);
+    this.berryList = bl;     
+            
+}
+
+ygDDPlayer.prototype = new YAHOO.util.DDProxy();
+
+ygDDPlayer.prototype.berryList = new Array();
+
+ygDDPlayer.prototype.initPlayer = function(id, sGroup) {
+	if (!id) { return; }
+
+    this.init(id, sGroup);
+    this.initFrame();
+    var s = this.getDragEl().style;
+    s.borderColor = "transparent";
+    // s.backgroundColor = "#cccccc";
+    s.opacity = 0.76;
+    s.filter = "alpha(opacity=76)";
+
+    // specify that this is not currently a drop target
+    this.isTarget = false;
+
+    this.originalStyles = [];
+
+    this.type = ygDDPlayer.TYPE;
+    this.slot = null;
+    this.startPos = YAHOO.util.Dom.getXY( this.getEl() );
+   
+}
+
+ygDDPlayer.prototype.startDrag = function(x, y) {
+	
+	var dragEl = this.getDragEl();
+	var clickEl = this.getEl();
+       
+       	dragEl.innerHTML = clickEl.innerHTML;
+	//dragEl.className = clickEl.className;
+    	//dragEl.style.color = clickEl.style.color;
+	//dragEl.style.backgroundColor = clickEl.style.backgroundColor;
+        //dragEl.style.visibility = clickEl.style.visibility;
+               
+ 	while (dragEl.hasChildNodes())	{
+        	 dragEl.removeChild(dragEl.firstChild);
+	}	
+       
+         var img = document.createElement('img');
+              img.src = 'interfaces/default/images/berry3.png';
+              img.height = 15;
+              img.width = 15;
+             img.border = 0;              
+          dragEl.appendChild(img);
+       
+        var added = true;
+
+      	var s = clickEl.style;
+	s.opacity = .1;
+	s.filter = "alpha(opacity=10)";
+
+	var targets = YAHOO.util.DDM.getRelated(this, true);
+	
+	for (var i=0; i<targets.length; i++) {
+		
+		var targetEl = this.getTargetDomRef(targets[i]);
+
+		if (!this.originalStyles[targetEl.id]) {
+			this.originalStyles[targetEl.id] = targetEl.className;
+		}
+
+		targetEl.className = "target";
+	}
+};
+
+ygDDPlayer.prototype.getTargetDomRef = function(oDD) {
+	if (oDD.player) {
+		return oDD.player.getEl();
+	} else {
+		return oDD.getEl();
+	}
+};
+
+ygDDPlayer.prototype.endDrag = function(e) {
+	// reset the linked element styles
+	var s = this.getEl().style;
+	s.opacity = 1;
+	s.filter = "alpha(opacity=100)";
+
+	this.resetTargets();
+};
+
+ygDDPlayer.prototype.resetTargets = function() {
+
+	// reset the target styles
+	var targets = YAHOO.util.DDM.getRelated(this, true);
+	for (var i=0; i<targets.length; i++) {
+		var targetEl = this.getTargetDomRef(targets[i]);
+		var oldStyle = this.originalStyles[targetEl.id];
+		if (oldStyle) {
+			targetEl.className = oldStyle;
+		}
+	}
+};
+
+var request_type = "GET";
+var addurlPath ="?a=pr&rt=r&ro=1&s=AddItem&c=&s1.id=2&o=XML&s1.item=";
+var delurlPath ="?a=pr&rt=r&ro=1&s=DeleteItem&c=&o=XML&s1.item=";
+var postdata = null;
+
+ygDDPlayer.prototype.onDragDrop = function(e, id) {
+	// get the drag and drop object that was targeted
+     var oDD;
+     var player = this;
+   
+    if ("string" == typeof id) {
+        oDD = YAHOO.util.DDM.getDDById(id);
+    } else {
+        oDD = YAHOO.util.DDM.getBestMatch(id);
+    }
+
+
+   var el = this.getEl();
+
+	// check if the slot has a player in it already
+	if (oDD.player) {
+		// check if the dragged player was already in a slot
+		if (this.slot) {
+	  		// check to see if the player that is already in the
+			// slot can go to the slot the dragged player is in
+			// YAHOO.util.DDM.isLegalTarget is a new method
+			if ( YAHOO.util.DDM.isLegalTarget(oDD.player, this.slot) ) {
+				YAHOO.util.DDM.moveToEl(oDD.player.getEl(), el);
+				this.slot.player = oDD.player;
+				oDD.player.slot = this.slot;
+			} else {
+				YAHOO.util.Dom.setXY(oDD.player.getEl(), oDD.player.startPos);
+				this.slot.player = null;
+				oDD.player.slot = null
+			}
+		} else {
+		        // the player in the slot will be moved to the dragged
+			// players start position
+			//oDD.player.slot = null;
+			//YAHOO.util.DDM.moveToEl(oDD.player.getEl(), el);
+		}
+	}else {
+		// Move the player into the emply slot
+		// I may be moving off a slot so I need to clear the player ref
+	   	if (this.slot) {
+			this.slot.player = null;
+		}
+	}
+
+     var  addurl = addurlPath + el.id;	
+     var addSuccess = function(o){ 
+                 var text = o.responseText;
+	         var result = o.responseXML;
+                 var items = result.getElementsByTagName('item');
+                 if (items.length > 0){
+                    var item = items[0];
+                    var berrybasket = YAHOO.util.Dom.get('berrybasket');
+        	    var berries = YAHOO.util.Dom.get('berries');
+                    player.berryList[player.berryList.length]= item;     
+                
+                    var itemID = item.getAttribute('collection')+":"+item.getAttribute('name');
+                    var parent =el.parentNode;
+                    parent.removeChild(el);
+ 	        	
+                    if (parent !=null && parent.id == "documentberries"){
+                         var root = YAHOO.util.Dom.get(itemID+":root");
+                         var section = YAHOO.util.Dom.get(itemID+":section");
+                         if(root!=null && root.id.indexOf(itemID) !=-1){
+                             parent.removeChild(root);
+                          }
+     
+	                  if(section!=null && section.id.indexOf(itemID) !=-1){
+                             parent.removeChild(section);
+        	          }                                                
+                     }
+                   
+
+                    if (!YAHOO.util.Dom.get('hideview') && player.berryList.length <13){
+                       
+                       while (berries.hasChildNodes()) {
+       	                   berries.removeChild(berries.firstChild);
+	                }
+                        
+                     for (var i =0; i < player.berryList.length; i++ ){
+                             var img = document.createElement('img');
+                              img.src = 'interfaces/default/images/berry3.png';
+                              img.height = 15;
+                              img.width = 15;
+                              img.border = 0;              
+                              berries.appendChild(img);
+                       }
+      	                                   
+	          }
+                 else{
+                      
+        
+                    if (YAHOO.util.Dom.get('hideview')){
+                      
+                        var berryBasket  = YAHOO.util.Dom.get('berrybasket');
+                        var berries  = YAHOO.util.Dom.get('berries');
+                        var doclist = YAHOO.util.Dom.get('doclist'); 
+                        var tid = el.id;                                  
+                        var berryItem; 
+                        var berryElement = document.createElement('li');
+                         for (var i in player.berryList){
+                             berryItem = player.berryList[i];
+                             var id = berryItem.getAttribute('collection')+":"+berryItem.getAttribute('name');
+                             if (id == tid){
+                               var title = berryItem.getAttribute('title');
+                               var root_title = berryItem.getAttribute('root_title');  
+                                if (root_title != ""){
+                                      root_title +=":";
+                                     }
+	    
+                                title = root_title+title;	
+                                if (title.length > 50){
+                                   title = title.substring(0,20)+" ... "+title.substr(title.length-35,35);
+                                }
+                                
+                               berryElement.appendChild(document.createTextNode(title));
+                               berryElement.setAttribute("class","berryitem");
+                               doclist.appendChild(berryElement);
+                               var heightStr =  berryBasket.style.height+"";
+                               var height =parseInt(heightStr.substring(0,heightStr.length-2)) +18;                             
+                               berryBasket.style.height = height;
+                               berries.style.height = height;
+                               break;
+                            }
+                         }
+                         }    
+                 
+                 }
+               }
+                
+                       
+
+         }
+
+     var addFailure = function(o){ }
+
+
+     var addcallback = {
+        	success:addSuccess,
+     	        failure:addFailure,  
+                argument:player
+                }
+    
+
+    var  delurl = delurlPath + el.id;	
+     var delSuccess = function(o){ 
+ 		 var result = o.responseXML;
+                    var parent =el.parentNode;
+                    if (parent == null) return;                   
+
+                    parent.removeChild(el);
+                     
+                    for (var i in player.berryList){
+                       var berry = player.berryList[i];
+                  
+                       var id = berry['collection']+":"+berry['name'];
+                       
+                       if (id == el.id){
+                             player.berryList.splice(i,1);
+                                    
+                             break;
+                         }
+
+                   }
+
+                   if (!parent.hasChildNodes()){
+                         var content =  YAHOO.util.Dom.get('content');
+                           while (content.hasChildNodes()) {
+		              content.removeChild(content.firstChild);
+	                }  
+                        content.appendChild(document.createTextNode('Your berry basket is empty.'));
+                     }
+                   var trashbin =  YAHOO.util.Dom.get('trashbin');
+                   if ( trashbin !=null){
+                         trashbin.style.background = 'url("interfaces/default/images/trash-full.png") 0 0 no-repeat';
+                  }
+              }                                       
+         
+
+     var delFailure = function(o){ }
+
+
+     var delcallback = {
+        	success:delSuccess,
+     	        failure:delFailure,  
+                argument:player
+                }
+    
+
+  if (id == 'berrybasket'){
+       YAHOO.util.Connect.asyncRequest(request_type , addurl , addcallback);         
+  }
+  else{
+        if (id == 'trashbin'){
+             YAHOO.util.Connect.asyncRequest(request_type , delurl , delcallback); 
+         }
+   }
+
+   this.resetTargets();  	
+   this.slot = oDD;	
+   this.slot.player = this;
+ 
+};
+
+ygDDPlayer.prototype.swap = function(el1, el2) {
+    var dom = YAHOO.util.Dom;
+	var pos1 = dom.getXY(el1);
+	var pos2 = dom.getXY(el2);
+	dom.setXY(el1, pos2);
+	dom.setXY(el2, pos1);
+};
+
+ygDDPlayer.prototype.onDragOver = function(e, id) {};
+
+ygDDPlayer.prototype.onDrag = function(e, id) {};
+
+
+
+
+
Index: /greenstone3/trunk/web/interfaces/default/style/berry.css
===================================================================
--- /greenstone3/trunk/web/interfaces/default/style/berry.css	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/style/berry.css	(revision 14125)
@@ -0,0 +1,317 @@
+
+
+div.globalwrapper{
+  font-family: sans-serif, arial, helvetica;
+  margin: 0 2em 0 4em; 
+  padding:0;
+ 
+}
+
+div#content{
+  font-family: sans-serif, arial, helvetica;
+  margin: 0.5em 0 0.5em 0;
+  padding: 0; 
+
+}
+
+div.banner{
+ margin:0;
+ padding:0;
+
+}
+
+div.pageinfo{
+  float:right;
+  text-align: right;
+  padding: 0;
+  margin:0 0 3px 0;	
+  width: 50%;
+}
+
+div.basketimage{
+  float:left;
+  width: 45%;
+  padding:0;
+  margin:0;
+
+}
+
+
+div.bannerextra {
+   clear: both;
+   padding: 0.2em 0 0 0;
+}
+
+/* home, help, preferences links */
+p.bannerlinks {
+  font-weight: bold;
+  margin:0;
+  padding:0;
+}
+
+
+p.bannertitle {
+  font-family: sans-serif, arial, helvetica;
+  font-size: 24px;
+  font-weight: bold;
+  white-space: nowrap;
+  margin: 0;
+  padding: 0.5em 0 0.5em 0em;
+  background: url("../images/tile13.jpeg") 0 0 repeat-y;
+ 
+}
+
+
+a.navlink{
+  vertical-align: top;
+  padding: 0.2em 0.5em 0 0;
+  color: black;
+  text-decoration: none; 
+  background-image: url("../images/bg_off.png");
+ }
+
+a.navlink:hover {
+   background-image: url("../images/bg_on.png");
+ }
+
+p.navbar{
+  text-align: center;
+   background: url("../images/bg_green.png") 0 0 repeat-x;
+   font-weight: bold;
+}
+
+span.navlink{
+   margin:0 3em  0 3em;
+   padding:0 0.5em 0 0.5em;
+   background-image: url("../images/bg_off.png");
+   cursor: pointer;
+}
+
+span.navlink:hover {
+   background-image: url("../images/bg_on.png");
+ }
+
+img#trashbin{
+ float:right;
+}
+
+span.berryradio{
+ cursor: pointer;
+ margin:0 3em  0 3em;
+ font-weight: bold;
+}
+
+.berrycheck{
+ font-size: 80%;  
+ cursor: pointer;
+ font-weight: bold;
+ margin: 0 0 0 0.5em;
+}
+
+#urlcheck{
+ float: left;
+ padding: 0;
+ margin: 0;
+ 
+}
+
+.pick {
+  visibility:hidden;
+}
+
+div#berrybasket {
+   float:right;
+   font-family:sans-serif;
+   height:120px;
+   width: 100px;
+   padding: 4px 5px 4px 4px;
+   background-color:#E0F0E0;
+   background: url("../images/berrybasket.png") 0 0 no-repeat;
+   margin:0;
+   font-size:100%;
+   text-align:center;
+   #border:1px solid #2E8B57;	
+   z-index:10;
+   cursor: pointer;
+ }
+
+div#baskethandle {
+  padding: 0;
+  cursor:move;
+  height: 30px;
+  width:auto;
+  #background-color:#eeeeee;
+   background:transparent;
+   margin:0 ;
+  }
+
+div#berries {
+  text-align:left;
+  height: auto;
+  margin: 0;
+  padding:0;
+  overflow: hidden;   
+}
+
+
+p#documentberries {
+   font-weight: bold;
+   font-size:90%;
+}
+
+.documentberry {
+  margin:0 2em 0 0;
+  padding:0;
+  visibility:hidden;
+}
+
+
+#doclist{
+  margin: 0;
+ 
+}
+
+.content{
+ font-family:sans-serif;
+ text-align:left;
+}
+
+li.berryitem {
+   padding: 0;
+   margin: 0 ;
+   color: black;
+   font-size: 90%;
+}
+
+li.berrydoc {
+  font-size: 90%;
+  cursor: pointer;
+  padding: 0 ;
+  margin: 0 1em 0 0; 
+}
+
+a.expandcontract {
+  font-size: 90%;
+  color: red
+}
+
+
+.item {
+  font-size: 90%;
+ 
+}
+
+a.fullview:visited{
+ color:red;
+}
+
+a#hideview:visited{
+ color:red;
+}
+
+a.fullview{
+  float:left;
+  font-size: 90%;
+  margin: 0 0 0 20px;
+  padding:0;
+  cursor: pointer;
+  color:red;  
+  text-decoration:none;
+ }
+
+a#hideView{
+  float:right;
+  font-size: 90%;
+  margin:0 20px 0 0;
+  padding:0;
+  color: red;
+  cursor: pointer;
+  text-decoration:none;
+}
+
+
+.berrydelete{
+   font-family:sans-serif;
+   background-color:#E0F0E0;
+   border:1px solid #2E8B57;   
+   padding: 4px  4px 4px 4px; 
+   font-weight: bold;
+   cursor: pointer;
+   width: 6em;
+   color: red;
+   font-size: 90%;
+}
+
+.sendbutton{
+   font-family:sans-serif;
+   background-color:#E0F0E0;
+   border:1px solid #2E8B57;   
+   padding: 4px  4px 4px 4px; 
+   font-weight: bold;
+   cursor: pointer;
+   width: 5em;
+   font-size: 90%;
+   margin: 1em 0 0 0;
+}
+
+.berrybutton{
+   font-family:sans-serif;
+   background-color:#E0F0E0;
+   border:1px solid #2E8B57;   
+   padding: 4px  4px 4px 4px; 
+   font-weight: bold;
+   cursor: pointer;
+   width: 10em;
+   font-size: 90%;
+}
+
+.mailinput {
+  border:1px solid #2E8B57; 
+  width: 20em;
+  height: 1.5em;
+  font-size: 90%
+}
+
+.mailitem{
+   text-align: left;
+ }
+
+
+textarea#pretextarea {
+  font-family:sans-serif;
+  border:1px solid #2E8B57; 
+  width: 100%;
+  height: 25em;
+  font-size: 90%;
+  margin: 0.5em 0 0 0;
+  padding:0;
+}
+
+div#trashbin{
+   float: right;
+   height: 60px;
+   width:  55px;
+   padding: 0;
+   background: url("../images/trash-empty.png") 0 0 no-repeat;
+   margin:0;
+   z-index:10;
+}
+
+div#binhandle{
+ height: 60px;
+ width:  55px;
+ cursor: move;
+}
+
+span.extralink {
+  cursor:pointer;
+  font-size:80%;
+  font-weight:bold;
+  margin:0 2em 0 0;
+  color:black;
+}
+
+span.extralink:hover {
+   color: #2E8B57;
+}
+
Index: /greenstone3/trunk/web/interfaces/default/style/core.css
===================================================================
--- /greenstone3/trunk/web/interfaces/default/style/core.css	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/style/core.css	(revision 14125)
@@ -0,0 +1,376 @@
+
+body {
+  padding:0;
+  margin:0;
+  font-family: sans-serif, arial, helvetica;   
+  background-image: url('../images/chalk.gif');
+  background-color: #fff; 
+  color: #000000 
+}
+
+/* this contains everything - all the other divs */
+#globalwrapper {
+  margin: .5em 3em 0 5em;
+}
+
+a:link
+{
+color: #339966;
+}
+
+a:visited
+{
+color: #066;
+}
+
+a:hover, a:active
+{
+color: #99CC33;
+}
+
+div#banner ul, ul#resultlist, ul#tocnodes, ul#docbuttons, ul.tocnode, ul#bannerlist, ul#navbarlist, ul#collectionlist, ul#servicelist, ul#classifierlist, ul#classifiernodelist, ul#queryitemlist{
+  list-style-type:none;
+  margin:0;
+  padding:0;
+}
+
+div#banner ul li, ul#bannerlist li, ul#navbarlist li {
+  display: inline;
+  margin:0;
+  padding:0;	
+}
+
+
+ul li>select, ul li>input {
+  padding: 0;
+  margin-left:5px;
+}
+
+
+div#banner {
+  margin: 0;
+  padding:0;
+  overflow: hidden;
+}
+
+div#banner p {
+  margin:0;
+  padding: 0;
+  float:left;
+  font-size: 16px;
+  text-align: left;
+  overflow:hidden	
+}
+
+div#banner p a {
+  background-image: url('../images/banner_bg.png');
+  background-repeat: repeat-y;
+}
+
+
+div#banner ul{
+  margin:0;
+  padding:0; 
+  float:right; 
+  font-size: 12px;  
+}
+
+div#banner a{
+  text-decoration: none;
+  color:#000000;
+}
+
+
+ul#bannerlist li a {
+  padding: 0 10px 0 10px; 
+  text-decoration: none;
+}
+
+ul#bannerlist li a:link, ul#bannerlist li a:visited
+{
+ background-color: #DEE79C;
+ background-image: url('../images/bg_off.png');
+ text-decoration: none
+}
+
+ul#bannerlist li a:hover{
+ background-color: #FFFF66;
+ background-image: url('../images/bg_on.png') ;
+ text-decoration: none
+}
+
+
+div#navbar{
+  clear:both;
+}
+
+ul#navbarlist{
+  margin:0;
+  padding:0; 
+  list-style-type: none; 
+  text-align:center;
+  width: 100%;
+  font-size: 80%;
+  background-image: url('../images/bg_green.png');	  
+  background-color: #99CC99
+ }
+
+ul#navbarlist li a {
+  padding: 0 20px 0 20px; 
+  margin: 0;
+  color: #000000; 
+  text-decoration: none;
+}
+
+ul#navbarlist li a:link, ul#navbarlist li a:visited{
+   background-image: url('../images/bg_off.png') ;
+ }
+
+ul#navbarlist li a:hover{
+  background-image: url('../images/bg_on.png') ;
+}
+
+
+ul#collectionlist li, ul#servicelist li{
+  display:block;
+  padding:0;
+  margin: .2em 0 0 0;
+  overflow:hidden;
+}
+
+
+ul#collectionlist img{
+  margin:0;
+  padding:0;
+  width: 150px;
+  height: 45px;
+  border: 1px solid black;
+  background-image: url('../images/collectimg_bg.png');
+  background-repeat: repeat-y;
+  overflow:hidden
+}
+
+ul#collectionlist li a.noimage{
+  display: block;
+  margin:0;
+  width: 145px;
+  height: 40px;
+  border: 1px solid black;
+  background-image: url('../images/collectimg_bg.png');
+  background-repeat: repeat-y;
+  overflow:hidden; padding-left:5px; padding-right:0; padding-top:5px; padding-bottom:0
+
+}
+
+ul#collectionlist li a{
+  font-size: 16px;
+  color: #000000;
+  text-decoration: none;  
+  font-weight: bold;
+}
+
+ul#servicelist li a{
+  margin:0 .5em 0 0;
+}
+
+ul#queryitemlist li{
+  display:block;
+  margin: .2em 0 .2em 0;
+}
+
+ul#classifierlist li{
+  list-style: none;
+  margin: 0 0 5px 0;
+  padding: 0;
+  display: block;
+  color:#000;
+}
+
+ul#classifierlist li#activeclassifier{
+  font-weight:bold;
+  padding: 0 0 0 5px;
+  margin:0 0 5px 0;
+}
+
+ ul#classifierlist li a:link, ul#classifierlist li a:visited  
+{
+   display:block;
+   margin:0;
+   background-image: url('../images/bg_off.png');
+   text-decoration: none; 
+   color:#000;
+   width:100%; padding-left:5px; padding-right:0; padding-top:2px; padding-bottom:2px
+ } 
+
+ul#classifierlist li a:hover, ul#classifierlist li a:active
+{
+  display:block;
+  margin:0;
+  background-image: url('../images/bg_on.png');
+  text-decoration: none; padding-left:5px; padding-right:0; padding-top:2px; padding-bottom:2px
+  
+}
+
+ul#classifierlist{
+   float:left;
+   font-size: 14px;
+   text-align: left;
+   width: 15%;
+   margin:0;
+   padding:0;
+}
+
+div#classifiers{
+  float:left;
+  width: 75%;
+  margin:0;
+  padding:0 0 0 10px;
+ }
+
+ul#classifiernodelist li{
+  list-style: none;
+  margin: 0;
+  padding: 5px 0 0 0;
+  display: block;
+ }
+
+ul.childrenlist{
+  margin: 0 0 0 0;
+  padding: 0 0 0 20px;
+  display: block;
+  width: 100%;
+}
+
+div#content{
+ clear: both;
+ overflow: hidden;
+ margin: .2em 0 0 0;
+}
+
+/* bg image set in style macro */
+div.divbar { 
+  clear: both; 
+  background-image: url('../images/bg_green.png'); 
+  width: 100%; 
+  text-align: center;
+  font-size:80%
+}
+
+
+/** query form style**/
+div#queryform{
+
+}
+
+/** search result style */
+div#terminfo{
+
+}
+
+div#matchdocs{
+
+}
+
+div.resultnavigation{
+ margin: 0;
+ padding:0;
+}
+
+ul#resultlist li{
+  display:block;
+}
+
+
+div.documenttext { clear: both; } /* come after any floating divs */
+
+div#documentheading{
+  font-size: 16pt;
+  font-weight: bold;
+}
+
+div#documentinfo { 
+  float:left;
+  padding:0;
+  margin:0;
+  width:24%;
+} 
+
+div#toc{
+  float:left;
+  text-align:left;
+  width:60%;
+  padding:0;
+  margin:0; 
+}
+
+ul#docbuttons li {
+   display: block;
+  font-size: 11px;
+  font-weight: bold;
+  background: #f7e7c5;
+  margin: 1px;
+  border: 1px solid #eeddbb;
+  text-align: center;
+  vertical-align: middle;
+  height: 30px; /* IE6 and NS4 treat width/height as min-width/min-height */
+  width: 110px;
+}
+
+
+ul#tocnodes li{
+ margin: 0;
+ padding: 5px 0 0 0;
+ display:block;
+}
+
+ul.tocnode {
+  margin:0;
+  padding:5px 0 0 20px;
+}
+
+ul.tocnode  a{
+ margin: 0;
+ padding:0 5px 0 0;
+ }
+
+span.bold{
+  font-weight: bold;	   
+}
+
+div.documentarrows{
+  clear: both; 
+  margin: 0 0 0 0;
+  padding: 1em 0 0 0;   
+}
+
+img.lessarrow{
+  float:left;
+  border: none;  
+}
+
+img.morearrow{
+  float:right;
+  border:none; 
+}
+
+div.formheading{
+  font-size: 16pt;
+  font-weight: bold;
+  margin: .5em 0 0;
+  padding:0;
+}
+
+ul#presprefs li, ul#berrybasketprefs li, ul#searchprefs li{
+  display: block;
+} 
+
+
+div.phrasebrowse{
+  text-align:center;
+  padding:0;
+  margin: .5em 0 .5em 0;   
+}
+
+div.QuickSearch {
+  float: right;
+}
Index: /greenstone3/trunk/web/interfaces/default/transform/about.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/default/transform/about.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/transform/about.xsl	(revision 14125)
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+  
+  <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+  
+  <xsl:output method="html"/>  
+
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="/page/pageResponse/*/displayItem[@name='name']"/>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+  <xsl:template match="pageResponse">
+     <xsl:variable name="collName" select="/page/pageRequest/paramList/param[@name='c']/@value"/>
+    <xsl:apply-templates select="collection|serviceCluster"><xsl:with-param name="collName" select="$collName"/></xsl:apply-templates>
+   </xsl:template>
+  
+  <xsl:template match="collection|serviceCluster">
+    <xsl:param name="collName"/>
+    <xsl:call-template name="standardPageBanner">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+    <xsl:call-template name="navigationBar">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>     
+    <div id="content"> 
+        <xsl:value-of select="displayItem[@name='description']" disable-output-escaping="yes"/>
+        <xsl:apply-templates select="serviceList">
+          <xsl:with-param name="collName" select="$collName"/>
+        </xsl:apply-templates>
+    </div>
+  </xsl:template>
+  
+  
+  <xsl:template match="serviceList">
+    <xsl:param name="collName"/>
+    <h3><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'about.services')"/></h3>
+    <xsl:choose>
+      <xsl:when test="service">
+	<xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'about.servicehelp')"/>
+      </xsl:when>
+      <xsl:otherwise>
+	<xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'about.noservices')"/>
+      </xsl:otherwise>
+    </xsl:choose>
+    
+    <xsl:if test="service">
+     <ul id="servicelist">  	
+      <xsl:for-each select="service">
+	    <xsl:variable name="action"><xsl:choose>
+	      <xsl:when test="@type='query'">q</xsl:when>
+	      <xsl:when test="@type='browse'">b</xsl:when>
+	      <xsl:when test="@type='process'">pr</xsl:when>
+	      <xsl:when test="@type='applet'">a</xsl:when>
+	      <xsl:otherwise>DO_NOT_DISPLAY</xsl:otherwise>
+	    </xsl:choose></xsl:variable>
+	   <xsl:if test="$action !='DO_NOT_DISPLAY'">
+	       <li><a href="{$library_name}?a={$action}&amp;rt=d&amp;s={@name}&amp;c={$collName}"><xsl:value-of select="displayItem[@name='name']"/></a><xsl:value-of select="displayItem[@name='description']"/></li>
+	  </xsl:if>
+  	</xsl:for-each>
+      </ul> 
+     </xsl:if> 
+  </xsl:template>
+
+</xsl:stylesheet>  
+
Index: /greenstone3/trunk/web/interfaces/default/transform/applet.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/default/transform/applet.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/transform/applet.xsl	(revision 14125)
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+  
+  <xsl:include href="style.xsl"/>
+  
+  <xsl:output method="html"/>  
+
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="pageResponse/service/applet"/>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName"><xsl:value-of select="../pageRequest/paramList/param[@name='c']/@value"/></xsl:variable>
+     <xsl:call-template name="standardPageBanner">
+	<xsl:with-param name="collName" select="$collName"/>
+      </xsl:call-template>
+    
+    <xsl:call-template name="navigationBar">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>      
+    <div class="phrasebrowse">
+      <xsl:copy-of select="service/applet"/>
+    </div>
+    </xsl:template>
+</xsl:stylesheet>  
+
Index: /greenstone3/trunk/web/interfaces/default/transform/berry.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/default/transform/berry.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/transform/berry.xsl	(revision 14125)
@@ -0,0 +1,743 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+
+  <!--<xsl:include href="style.xsl"/>-->
+  <xsl:include href="service-params.xsl"/>
+  <xsl:include href="berrytools.xsl"/>
+
+  <xsl:output method="html"/>  
+
+  <xsl:param name="library_name"/>
+  
+   <!-- the main page layout template is here -->
+  <xsl:template match="page">
+    <html>
+      <xsl:call-template name="pageHead"/>	 
+      <body class="bgimage">
+	<div class='globalwrapper'>
+	  <xsl:apply-templates select="pageResponse"/>
+	</div>
+      </body>
+    </html>
+  </xsl:template>
+
+  <!-- put a space in the title in case the actual value is missing - mozilla will not display a page with no title-->
+  <xsl:template name="pageHead">
+    <head>
+      <title>
+	<xsl:call-template name="pageTitle"/>
+      </title>
+      <xsl:call-template name="pageStyle"/>
+    </head>
+  </xsl:template>
+  
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="/page/pageResponse/serviceCluster/metadataList/metadata[@name='Title']"/>
+    Berry Basket
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle" >
+    <xsl:call-template name="styleSheet" />
+    <xsl:call-template name="loadLibrary" />
+    <xsl:call-template name="buildContent" />   
+    <!-- <xsl:call-template name="showMailBox" />-->
+  </xsl:template>    
+  
+  <xsl:template match="pageResponse">
+    <xsl:variable name="clusterName"><xsl:value-of select="/page/pageRequest/paramList/param[@name='c']/@value"/></xsl:variable>
+    <xsl:call-template name="berryPageBanner" />
+    <xsl:apply-templates select="paramList"/>
+    <div id="content" ><span></span></div> 
+    <xsl:call-template name="footBanner" />
+  </xsl:template>
+  
+
+  <xsl:template match="collection">
+    <xsl:for-each select="item">
+      <xsl:text disable-output-escaping="yes">
+	var  doc = new Array();             
+      </xsl:text>
+      <xsl:for-each select="@*">
+	<xsl:text disable-output-escaping="yes">
+	  doc["</xsl:text><xsl:value-of select="name()" /><xsl:text disable-output-escaping="yes">"]='</xsl:text><xsl:value-of select="." /><xsl:text disable-output-escaping="yes">'; </xsl:text>   
+      </xsl:for-each>
+      <xsl:text disable-output-escaping="yes"> 
+	docList[docList.length] = doc; 
+      </xsl:text>  
+    </xsl:for-each>     
+  </xsl:template>
+  
+  
+  <xsl:template name="buildContent">
+    <script type="text/javascript">
+      <xsl:text disable-output-escaping="yes">
+	var previousView;
+	var docList = new Array();
+	var urlonly = false;
+	var mailinfo = new Array();
+	mailinfo['address'] = "To: ";
+	mailinfo['cc'] = "CC: ";
+	mailinfo['bcc'] = "Bcc: ";
+	mailinfo['subject'] = "Subject: "; 
+	var textwin;
+	var mailwin;
+      </xsl:text>
+      <xsl:apply-templates select="/page/pageResponse/collection" />       
+      
+      <xsl:text disable-output-escaping="yes">
+    
+       function navigate(e){   
+             var target = e.target;
+       
+	     if (target.id.toLowerCase() == 'fullview'){  
+                  showFullView();
+              }
+
+             if (target.id.toLowerCase() == 'textview'){       
+               showTextView();
+             }
+
+             if (target.id.toLowerCase() == 'email'){       
+               showEmail();
+            }
+
+            if (target.id.toLowerCase() == 'sendmail'){       
+               sendMail();
+            }
+            
+           
+
+            if (target.id.toLowerCase() == 'urlcheck' &amp;&amp; urlonly){
+               var urlcheck = YAHOO.util.Dom.get('urlcheck');
+               urlcheck.src = 'interfaces/default/images/check3.gif';              
+               var parea  =YAHOO.util.Dom.get('pretextarea');       
+               urlonly = false;
+               populateUrlsAndMetadata(parea);
+               return;
+               
+            }
+
+            if (target.id.toLowerCase() == 'urlcheck' &amp;&amp; !urlonly ){ 
+                var urlcheck = YAHOO.util.Dom.get('urlcheck');
+                urlcheck.src = 'interfaces/default/images/check4.gif';                       
+                var parea  =YAHOO.util.Dom.get('pretextarea');
+                populateUrls(parea);        
+                urlonly = true;
+                return;
+             } 
+
+            if (target.id.toLowerCase() == 'extextview' ){
+               if (textwin != null){
+                   textwin.close();
+               }
+
+               textwin = window.open("","Berry basket plain text view","status=1,width=450,height=300");
+               textwin.moveTo(0,0);
+               var content = document.createElement('div');
+                buildPreview(content);
+                var body = textwin.document.getElementsByTagName('body')[0]; 
+                body.appendChild(content);
+                var prearea =  textwin.document.getElementsByTagName('textarea')[0];
+                prearea.cols = '55';
+                prearea.rows = '15';        
+             }
+
+             if (target.id.toLowerCase() == 'exemail' ){
+               if (mailwin != null){
+                   mailwin.close();
+               }
+               mailwin = window.open("","Berry basket mail to a friend","status=1,width=450,height=350");
+               mailwin.moveTo(0,0);
+               var content = document.createElement('div');
+               getEmailContent(content);
+               var body = mailwin.document.getElementsByTagName('body')[0]; 
+               body.appendChild(content);           
+                var prearea =  mailwin.document.getElementsByTagName('textarea')[0];
+                prearea.cols = '50';
+                prearea.rows = '11'; 
+             }
+              
+        }
+
+        function showFullView(){
+          
+             var content =  YAHOO.util.Dom.get('content'); 
+             var fullview =  YAHOO.util.Dom.get('fullview');
+
+              if (previousView != null){
+                 previousView.style.backgroundImage =  'url("interfaces/default/images/bg_on.png")'; 
+              } 
+              previousView = fullview;
+              previousView.style.backgroundImage =  'url("interfaces/default/images/bg_green.png")';
+
+               while (content.hasChildNodes()) {
+		 content.removeChild(content.firstChild);
+	       }                        
+           
+             if (docList.length == 0){
+                 content.appendChild(document.createTextNode("Your berry basket is empty."));
+                 return;
+              }
+
+ 
+            var trashbin = document.createElement('div');
+            trashbin.id ='trashbin';   
+            var binhandle = document.createElement('div');
+            binhandle.id = 'binhandle';   
+            binhandle.appendChild(document.createElement('span'));          
+            trashbin.appendChild(binhandle) 
+
+            content.appendChild(trashbin);
+
+            var dd = new ygDDOnTop('trashbin');
+            dd.setHandleElId('binhandle');      
+            new YAHOO.util.DDTarget('trashbin','trash');
+        
+            var dlist = document.createElement('div');
+            content.appendChild(dlist);                          
+            var ol =   document.createElement('ol');            
+            dlist.appendChild(ol); 
+
+             for (var i in docList){
+               var doc = docList[i];
+               var li = document.createElement('li'); 
+               var a = document.createElement('a'); 
+               var text ="";
+               a.href ="?a=d&amp;c="+doc['collection']+"&amp;d="+doc['name'];
+               a.appendChild(document.createTextNode(doc['title'])); 
+                if (doc['root_title'] != ""){
+                     li.appendChild(document.createTextNode(doc['root_title']+": ")); 
+                   }               
+               li.appendChild(a);
+               var metadata = "";
+               for (var metaItem in doc &amp;&amp; metaItem != 'title'){
+                    metadata = "\n"+metaItem+": "+ doc[metaItem]+"\n";
+               }
+               text +=metadata+"\n";
+               li.appendChild(document.createTextNode(text));
+               li.id = doc['collection']+":"+ doc['name']; 
+               li.className = 'berrydoc';
+               ol.appendChild(li);
+                new ygDDPlayer(li.id,'trash',docList); 
+         }
+
+         /**          
+           var extra = document.createElement('div');
+           var textview =  document.createElement('span'); 
+           textview.id = 'extextview';
+           textview.className = 'extralink';   
+           textview.appendChild(document.createTextNode("plain text version"));                   
+           var email =  document.createElement('span');
+           email.appendChild(document.createTextNode("email to a friend"));
+           email.id = 'exemail';      
+           email.className = 'extralink';    
+           extra.appendChild(textview);
+           extra.appendChild(email);
+           content.appendChild(extra);
+         **/ 
+        }
+
+       function showTextView(){
+             var content =  YAHOO.util.Dom.get('content'); 
+             var textview =  YAHOO.util.Dom.get('textview');
+
+              if (previousView != null &amp;&amp; textview !=null){
+                 previousView.style.backgroundImage =  'url("interfaces/default/images/bg_on.png")'; 
+              } 
+
+             if (textview !=null){
+               previousView = textview;
+               previousView.style.backgroundImage =  'url("interfaces/default/images/bg_green.png")';
+             }
+
+               while (content.hasChildNodes()) {
+		 content.removeChild(content.firstChild);
+	       }                        
+           
+             if (docList.length == 0){
+                content.appendChild(document.createTextNode("Your berry basket is empty."));
+                return;
+              }
+
+             buildPreview(content);   
+
+        
+       }
+
+       function getEmailContent(content){
+           var item ;
+           var tr;
+           var td;
+           var input;
+           
+           table = document.createElement('table');
+           table.setAttribute("class","mailtable");          
+
+          for (item in mailinfo){
+  	   tr = document.createElement('tr');       
+           td = document.createElement('td');
+           td.setAttribute("class","mailitem");
+           td.appendChild(document.createTextNode(mailinfo[item]));
+           tr.appendChild(td);
+ 
+           td = document.createElement('td');
+           input = document.createElement('input'); 
+           input.setAttribute("id", item);
+           input.setAttribute("class", "mailinput");
+           input.setAttribute("type", "text");
+           td.appendChild(input);
+           tr.appendChild(td);	        
+           table.appendChild(tr);
+          
+          }
+
+ 	   // an empty line
+           tr = document.createElement('tr');
+           td = document.createElement('td');
+           td.appendChild(document.createElement('br'));
+	   tr.appendChild(td);
+  	   table.appendChild(tr);
+
+	   content.appendChild(table);
+          
+           buildPreview(content);   
+
+           //send button
+	   input = document.createElement('input'); 
+           input.setAttribute("id", 'sendmail');
+           input.setAttribute("class", "sendbutton");
+           input.setAttribute("type", "button");
+           input.setAttribute("value", "send");        
+           content.appendChild(input);
+           
+        }
+
+      
+        function showEmail(){
+          
+             var content =  YAHOO.util.Dom.get('content'); 
+             var email =  YAHOO.util.Dom.get('email');
+
+              if (previousView != null &amp;&amp; email !=null ){
+                 previousView.style.backgroundImage =  'url("interfaces/default/images/bg_on.png")'; 
+              } 
+              
+              if (email != null){
+                previousView = email;
+               previousView.style.backgroundImage =  'url("interfaces/default/images/bg_green.png")';
+             }
+               while (content.hasChildNodes()) {
+		 content.removeChild(content.firstChild);
+	       }                        
+           
+             if (docList.length == 0){
+                content.appendChild(document.createTextNode("Your berry basket is empty."));
+                return;
+              }
+
+                   
+           var item ;
+           var tr;
+           var td;
+           var input;
+           
+           table = document.createElement('table');
+           table.setAttribute("class","mailtable");          
+
+          for (item in mailinfo){
+  	   tr = document.createElement('tr');       
+           td = document.createElement('td');
+           td.setAttribute("class","mailitem");
+           td.appendChild(document.createTextNode(mailinfo[item]));
+           tr.appendChild(td);
+ 
+           td = document.createElement('td');
+           input = document.createElement('input'); 
+           input.setAttribute("id", item);
+           input.setAttribute("class", "mailinput");
+           input.setAttribute("type", "text");
+           td.appendChild(input);
+           tr.appendChild(td);	        
+           table.appendChild(tr);
+          
+          }
+
+ 	   // an empty line
+           tr = document.createElement('tr');
+           td = document.createElement('td');
+           td.appendChild(document.createElement('br'));
+	   tr.appendChild(td);
+  	   table.appendChild(tr);
+
+	   content.appendChild(table);
+          
+           buildPreview(content);   
+
+           //send button
+	   input = document.createElement('input'); 
+           input.setAttribute("id", 'sendmail');
+           input.setAttribute("class", "sendbutton");
+           input.setAttribute("type", "button");
+           input.setAttribute("value", "send");        
+           content.appendChild(input);
+
+         }
+
+
+         function buildPreview(parent){
+             var div = document.createElement('div');
+         
+         
+             var img =  document.createElement('img');
+             img.src = 'interfaces/default/images/check3.gif';
+             img.id = 'urlcheck'; 
+             div.appendChild(img);
+       
+             var urls = document.createElement('span');
+             urls.id = 'urls';
+             urls.className = 'berrycheck';
+             urls.appendChild(document.createTextNode('URL only'));
+             div.appendChild(urls);
+
+            // var urlsmetadata = document.createElement('span');
+            // urlsmetadata.id = 'urlsmetadata'
+            // urlsmetadata.className = 'berryradio';
+            // urlsmetadata.appendChild(document.createTextNode('URLs and Metadata'));
+              
+            // div.appendChild(urlsmetadata);
+          
+          
+             parent.appendChild(div);
+
+                       
+             var parea  = document.createElement('textarea');
+             parea.id = 'pretextarea';                        
+
+             parent.appendChild(parea);        
+          
+         
+             populateUrlsAndMetadata(parea);	    
+               
+                       	
+         }
+
+        
+       function populateUrls(parea){
+          var urls="";
+          var doc_url = document.URL;
+          var root_url = doc_url.substring(0,doc_url.indexOf('?'));
+           
+          for (var i in docList){
+              var doc = docList[i];
+              urls +=root_url+"?a=d&amp;c="+doc["collection"]+"&amp;d="+doc["name"]+"\n\n";  
+                     
+          }
+
+           parea.value = urls;
+            
+         }
+
+	 function populateUrlsAndMetadata(parea){
+                       
+              var doc_url = document.URL;
+              var root_url = doc_url.substring(0,doc_url.indexOf('?'));
+              var fulltext="";
+
+              for (var i in docList){
+                   var doc = docList[i];
+                   var url =root_url+"?a=d&amp;c="+doc['collection']+"&amp;d="+doc['name']+"\n";  
+                    for (var metaItem in doc){
+                        var metadata = metaItem+": "+ doc[metaItem]+"\n";
+                      }
+                     fulltext +=url+metadata+"\n";
+                 
+              }
+
+               parea.value = fulltext;
+                  
+           }                                                    	    		 
+	                     
+          function sendMail(){
+              var  url = "?a=pr&amp;rt=r&amp;ro=1&amp;s=SendMail&amp;c=";
+                     var request_type = "POST";
+                     var postdata = ""; 
+ 	             var i;	     
+                     //get checked items
+                      for (i in mailinfo)
+			{ 
+                         
+                          var input = YAHOO.util.Dom.get(i);  
+                          var value = input.value;  
+			  postdata +="&amp;s1."+i+"="+value;	
+			}                                   
+
+
+                       var content = YAHOO.util.Dom.get('pretextarea').value;
+                       
+                       content = content.replace(/&amp;/g,'-------');  
+                       postdata +="&amp;s1.content="+content;
+                                                                
+                      
+                        var callback = {
+     			   success:function(o){
+                                    var result = o.responseText;
+                                    alert(result);     
+	 			                                                                      
+                                	} ,
+     			    failure:function(o){
+                                        alert("Sending mail falied");    
+ 				     }    
+  			 }
+                                               
+ 	               
+   			YAHOO.util.Connect.asyncRequest(request_type , url , callback, postdata);         
+         }	
+
+        YAHOO.util.Event.addListener(window,'click', navigate);
+        YAHOO.util.Event.addListener(window,'load', showFullView);
+      </xsl:text>
+    </script>    
+  </xsl:template>
+
+  <xsl:template name="styleSheet">
+    <link rel="stylesheet" href="interfaces/default/style/core.css" type="text/css"/>  
+    <link rel="stylesheet" href="interfaces/default/style/berry.css" type="text/css"/>  
+  </xsl:template>
+  
+  <xsl:template name="showMailBox">
+    <script type="text/javascript">
+      <xsl:text disable-output-escaping="yes">
+	var show = false;	
+	var table;
+	var mailserver  = new Array();     
+	mailserver['host'] = "Mail Server: ";
+	mailserver['user'] = "User Name: ";
+	mailserver['password'] = "Password: ";
+	
+	var mailinfo = new Array();
+	mailinfo['address'] = "To: ";
+	mailinfo['cc'] = "CC: ";
+	mailinfo['bcc'] = "Bcc: ";
+	mailinfo['subject'] = "Subject: "; 
+	
+	function mailBoxUpdate(e) {
+		var target = e.target;
+		if (target.id.toLowerCase() == 'sendasemail' &amp;&amp; !show){
+	       	    showMailBox();
+                    show = true;
+                }
+                else{
+                    if (target.id.toLowerCase() == 'sendasemail' &amp;&amp; show){
+                       hideMailBox();
+                       show = false;
+                    }
+
+                     if (target.id.toLowerCase() == 'sendmail'){
+                      sendMail();
+                    }
+                }
+
+
+                	
+        }
+
+       function showMailBox(){
+           var mailbox = YAHOO.util.Dom.get('mailbox');  
+           if (table != null &amp;&amp; !show){
+               mailbox.appendChild(table);
+              return;
+           }
+                        
+           var item ;
+           var tr;
+           var td;
+           var input;
+           
+           table = document.createElement('table');
+           table.setAttribute("class","mailtable");          
+
+           // mail server
+           tr = document.createElement('tr');
+           td = document.createElement('td');
+           td.setAttribute("class","mailitem");
+           td.appendChild(document.createTextNode(mailserver['host']));
+           tr.appendChild(td);
+ 
+           td = document.createElement('td');
+           input = document.createElement('input'); 
+           input.setAttribute("id", 'host');
+           input.setAttribute("class", "mailinput");
+           input.setAttribute("type", "text");
+           td.appendChild(input);
+           td.appendChild(document.createTextNode(' e.g. webmail.cs.waikato.ac.nz'));
+           tr.appendChild(td);	        
+           table.appendChild(tr);
+         
+           //user name 
+	   tr = document.createElement('tr');
+           td = document.createElement('td');
+           td.setAttribute("class","mailitem");
+           td.appendChild(document.createTextNode(mailserver['user']));
+           tr.appendChild(td);
+           td = document.createElement('td');
+           input = document.createElement('input'); 
+           input.setAttribute("id", 'user');
+           input.setAttribute("class", "mailinput");
+           input.setAttribute("type", "text");
+           td.appendChild(input);
+           tr.appendChild(td);	        
+           table.appendChild(tr);
+
+           //password 	
+	   tr = document.createElement('tr');
+           td = document.createElement('td');
+           td.setAttribute("class","mailitem");
+           td.appendChild(document.createTextNode(mailserver['password']));
+           tr.appendChild(td);
+           td = document.createElement('td');
+           input = document.createElement('input'); 
+           input.setAttribute("id", 'password');
+           input.setAttribute("class", "mailinput");
+           input.setAttribute("type", "password");
+           td.appendChild(input);
+           tr.appendChild(td);	        
+           table.appendChild(tr);
+
+           // an empty line
+           tr = document.createElement('tr');
+           td = document.createElement('td');
+           td.appendChild(document.createElement('br'));
+	   tr.appendChild(td);
+  	   table.appendChild(tr);
+
+          for (item in mailinfo){
+  	   tr = document.createElement('tr');       
+           td = document.createElement('td');
+           td.setAttribute("class","mailitem");
+           td.appendChild(document.createTextNode(mailinfo[item]));
+           tr.appendChild(td);
+ 
+           td = document.createElement('td');
+           input = document.createElement('input'); 
+           input.setAttribute("id", item);
+           input.setAttribute("class", "mailinput");
+           input.setAttribute("type", "text");
+           td.appendChild(input);
+           tr.appendChild(td);	        
+           table.appendChild(tr);
+          
+          }
+
+ 	// an empty line
+           tr = document.createElement('tr');
+           td = document.createElement('td');
+           td.appendChild(document.createElement('br'));
+	   tr.appendChild(td);
+  	   table.appendChild(tr);
+
+	//send button
+	   tr = document.createElement('tr');
+       	   td = document.createElement('td');
+           td.setAttribute("class","mailitem");
+           input = document.createElement('input'); 
+           input.setAttribute("id", 'sendmail');
+           input.setAttribute("class", "sendbutton");
+           input.setAttribute("type", "button");
+           input.setAttribute("value", "send");
+           td.appendChild(input);
+           tr.appendChild(td);	        
+           table.appendChild(tr);
+
+           
+          mailbox.appendChild(table);
+         }            
+     
+
+       function hideMailBox(){
+          var mailbox = YAHOO.util.Dom.get('mailbox');	
+          while (mailbox.hasChildNodes()) {
+		mailbox.removeChild(mailbox.firstChild);
+	   }
+         }
+      
+         function sendMail(){
+              var  url = "?a=pr&amp;rt=r&amp;ro=1&amp;s=SendMail&amp;c=";
+                     var request_type = "POST";
+                     var postdata = ""; 
+ 	             var i;	     
+                     //get checked items
+                      for (i in mailinfo)
+			{ 
+                         
+                          var input = YAHOO.util.Dom.get(i);  
+                          var value = input.value;  
+			  postdata +="&amp;s1."+i+"="+value;	
+			}                                   
+
+
+                       for (i in mailserver){
+                          var input = YAHOO.util.Dom.get(i);  
+                          var value = input.value; 
+                           postdata +="&amp;s1."+i+"="+value;
+                        }
+
+                       var content = YAHOO.util.Dom.get('pretextarea').value;
+                       
+                       content = content.replace(/&amp;/g,'-------');  
+                       postdata +="&amp;s1.content="+content;
+                                                                
+                      
+                        var callback = {
+     			   success:function(o){
+                                    var response = o.responseXML;
+            	                       
+	 			         alert(response.getAttribute('status'));                                                               
+                                	} ,
+     			    failure:function(o){
+                                        alert("Sending mail falied");    
+ 				     }    
+  			 }
+                                               
+ 	               
+   			YAHOO.util.Connect.asyncRequest(request_type , url , callback, postdata);         
+                 }	
+
+              
+            YAHOO.util.Event.addListener(window,'click',mailBoxUpdate );
+
+      </xsl:text> 
+    </script>
+  </xsl:template>
+  
+  <xsl:template name="berryPageBanner">
+    <div class='banner'>
+      <div class='pageinfo'>
+	<p class='bannerlinks'>
+	  <a class='navlink' href='{$library_name}?a=p&amp;sa=home' title='Library home page' >HOME</a>
+	  <a class='navlink' href='{$library_name}?a=p&amp;sa=help&amp;c='  title='Help pages' >HELP</a>
+	  <a class='navlink' href='{$library_name}?a=p&amp;sa=pref&amp;c=' title='Change your interface preferences'>PREFERENCES</a>
+	</p>      
+      </div>
+      <div class='basketimage'><p class='bannertitle'>Berry Basket</p></div>        
+    </div>
+    <div class="bannerextra"></div>
+    
+    <div >
+      <p class='navbar'><span id='fullview' class='navlink'>full view</span><span id='textview' class='navlink'>plain text version</span><span id='email' class='navlink'>email to a friend</span></p>
+    </div> 
+  </xsl:template>
+  
+  <xsl:template name="footBanner">
+    <div >
+      <p class='navbar'><span >powered by greenstone3</span></p>
+    </div> 
+  </xsl:template>
+  
+</xsl:stylesheet>  
+
Index: /greenstone3/trunk/web/interfaces/default/transform/berrytools.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/default/transform/berrytools.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/transform/berrytools.xsl	(revision 14125)
@@ -0,0 +1,402 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+
+  <xsl:param name="berryBaskets"/>
+  
+  <xsl:template name="berrybasket">
+    <div id="berrybasket" class="hide" >
+      <div id="baskethandle"><span></span></div>
+      <div id ="berries"><span></span></div>
+    </div>
+  </xsl:template>
+  
+  <xsl:template name="documentBerryBasket">
+    <xsl:param name="collName"/>
+    <xsl:param name="selectedNode"/>
+    <xsl:param name="rootNode"/>
+    <xsl:param name="docType" />
+    <div id="berrybasket" class="hide" >
+      <div id="baskethandle"><span></span></div>
+      <div id ="berries" ><span></span></div>
+    </div>
+    <xsl:choose>
+      <xsl:when test="$selectedNode = $rootNode">
+	<p id="documentberries">    
+	  <img class='pick'  id="{$collName}:{$rootNode}" src="interfaces/default/images/berry3.png" alt="in basket" width="15" height="15" border="0"/><span id="{$collName}:{$rootNode}:root" class="documentberry">the whole document</span></p>       
+      </xsl:when>
+      <xsl:otherwise>
+	<p id="documentberries">    
+	  <img class='pick'  id="{$collName}:{$rootNode}" src="interfaces/default/images/berry3.png" alt="in basket" width="15" height="15" border="0"/><span id="{$collName}:{$rootNode}:root" class="documentberry">the whole document</span><img class='pick'  id="{$collName}:{$selectedNode}" src="interfaces/default/images/berry3.png" alt="in basket" width="15" height="15" border="0"/><span id="{$collName}:{$selectedNode}:section" class="documentberry">the current section</span></p>
+      </xsl:otherwise> 
+    </xsl:choose>
+  </xsl:template>
+
+  
+  <xsl:template name="loadLibrary">
+    <script type="text/javascript" src="interfaces/default/js/YAHOO.js"><xsl:text disable-output-escaping="yes"> </xsl:text></script>
+    <script type="text/javascript" src="interfaces/default/js/event.js"><xsl:text disable-output-escaping="yes"> </xsl:text></script>
+    <script type="text/javascript" src="interfaces/default/js/connection.js"><xsl:text disable-output-escaping="yes"> </xsl:text></script>
+    <script type="text/javascript" src="interfaces/default/js/dom.js"><xsl:text disable-output-escaping="yes"> </xsl:text></script>
+    <script type="text/javascript" src="interfaces/default/js/dragdrop.js"><xsl:text disable-output-escaping="yes"> </xsl:text></script>
+    <script type="text/javascript" src="interfaces/default/js/ygDDPlayer.js"><xsl:text disable-output-escaping="yes"> </xsl:text></script>
+    <script type="text/javascript" src="interfaces/default/js/ygDDOnTop.js"><xsl:text disable-output-escaping="yes"> </xsl:text></script>
+    
+  </xsl:template>
+  
+  <xsl:template name="js-library">
+    <xsl:call-template name="loadLibrary" />	
+    <xsl:call-template name="basketCheckout" />
+  </xsl:template> 
+  
+  <!-- should be called for a documentNode -->
+  <xsl:template name="addBerry">
+    <xsl:param name="collName"/>
+    <td valign="top"><img class='pick' id="{$collName}:{@nodeID}" src="interfaces/default/images/berry3.png" alt="in basket" width="15" height="15" border="0"/></td>
+  </xsl:template>
+  
+  <xsl:template name="basketCheckout">
+    <script type="text/javascript">
+      <xsl:text disable-output-escaping="yes">
+      //used to stored the current items in berrybasket, including collection name, document id and dodument title 
+      //in the format of collection:id:[title], it is updated when the page is loaded (reloaded) or the user adds
+      // new items in the berry basket (see ygDDplayer.js). It is used to show the contents of the berry basket. 
+     var berryList =  new Array();
+     var show = false;    
+ 
+     // the default width and height of the berry basket
+     var oldHeight=90;
+     var oldWidth=140;
+     var oldBg;
+
+     var dd = new ygDDOnTop('berrybasket');
+     dd.setHandleElId('baskethandle');
+
+     var checkout = function(){
+       var request_type = "GET";
+       var url = "?a=pr&amp;rt=r&amp;ro=1&amp;s=ItemNum&amp;o=XML&amp;c="; 
+ 
+         var responseSuccess = function(o){
+	     var response = o.responseXML;
+             var size = response.getElementsByTagName('size').item(0).getAttribute('value');       
+           
+             var items = response.getElementsByTagName('item');
+             
+             for (var i=0;i &lt; items.length ; i++ ){
+ 
+                 // remove berries images from if the berry basket has already contains this item  
+                
+                 var itemID = items[i].getAttribute('collection')+":"+items[i].getAttribute('name');
+                 var item =  YAHOO.util.Dom.get(itemID);
+                 if (item != null){
+                    var parent = item.parentNode;
+                    parent.removeChild(item);
+                   
+                   if (parent !=null &amp;&amp; parent.id == "documentberries"){
+                         var root = YAHOO.util.Dom.get(itemID+":root");
+                         var section = YAHOO.util.Dom.get(itemID+":section");
+                         if(root!=null &amp;&amp; root.id.indexOf(itemID) !=-1){
+                             parent.removeChild(root);
+                          }
+     
+	                  if(section!=null &amp;&amp; section.id.indexOf(itemID) !=-1){
+                             parent.removeChild(section);
+        	          }
+                      
+                          
+                     }
+                 }
+                                
+                  berryList[berryList.length] = items[i];                   	
+	      }
+
+               //add berryimage into the berry basket
+                updateBerryImages();         
+             
+                // set berries images visible
+             // they are set to be invisible to prevent flickering when first loaded (see berry.css) 
+            
+             var berries =document.getElementsByTagName('img');
+	     var berrybasket = new YAHOO.util.DDTarget('berrybasket','basket');
+           
+             for (var j=0; j &lt; berries.length; j++){
+          
+                  var berry = berries[j]; 
+                   var parent = berry.parentNode;
+                   
+                   
+                   if (parent !=null &amp;&amp; parent.id == "documentberries"){
+                         var root = YAHOO.util.Dom.get(berry.id+":root");
+                         var section = YAHOO.util.Dom.get(berry.id+":section");
+                         if(root!=null &amp;&amp; root.id.indexOf(berry.id) !=-1){
+                             root.style.visibility ="visible" ;
+                          }
+     
+	                  if(section!=null &amp;&amp; section.id.indexOf(berry.id) !=-1){
+                             section.style.visibility ="visible" ;
+        	          }
+                      
+                          
+                     }  
+
+               if (berry.className  &amp;&amp;  berry.className  == 'pick')
+                  { 
+                    berry.style.visibility = "visible";
+                    new ygDDPlayer(berry.id,'basket',berryList); 
+                  }   
+     	      
+             }
+           
+           }
+
+         var responseFailure = function(o){
+             
+          }  
+
+        var callback = {
+        success: responseSuccess,
+        failure: responseFailure 
+      }
+
+      YAHOO.util.Connect.asyncRequest(request_type , url , callback);
+   }
+
+    function updateBerryImages(){
+     
+      for (var i =0;i &lt; berryList.length &amp;&amp; i &lt;12 ; i++ ){
+               var berries = YAHOO.util.Dom.get('berries');
+               var img = document.createElement('img');
+               img.src = 'interfaces/default/images/berry3.png';
+               img.height = 15;
+               img.width = 15;
+               img.border = 0;              
+               berries.appendChild(img);
+          }
+
+    }
+
+    function basketUpdate(e) {
+		var target = e.target;
+               
+		if ((target.id.toLowerCase() == 'berrybasket' || target.id.toLowerCase() == 'berries')  &amp;&amp; !show){
+	       	    showBasket();
+                    show = true;
+                }
+                else{
+                    if (target.id.toLowerCase() == 'hideview' &amp;&amp; show){
+                       hideBasket();
+                       show = false;
+                    }
+                }
+           
+            if (target.className == 'pick'){
+              addBerry(target);
+            }
+            
+        }
+
+     function showBasket() {
+        var berryBasket  = YAHOO.util.Dom.get('berrybasket');  
+        var basketHandle = YAHOO.util.Dom.get('baskethandle'); 
+        var berries = YAHOO.util.Dom.get('berries');   
+        var div = document.createElement('div');
+        var list = document.createElement('ol');
+        var width = 500;
+        var height = 40;
+        var i=0;
+ 
+        list.id = 'doclist';
+      
+       //remove berryImages in the berry basket 
+       while (berries.hasChildNodes()) {
+       	  berries.removeChild(berries.firstChild);
+	}
+
+       while (basketHandle.hasChildNodes()) {
+       	  basketHandle.removeChild(basketHandle.firstChild);
+	}
+
+       for (i in berryList){
+            var berryItem = berryList[i];
+            var berryElement = document.createElement('li');
+            var title = berryItem.getAttribute('title');
+            var root_title = berryItem.getAttribute('root_title'); 
+            var id = berryItem.getAttribute('collection')+":"+berryItem.getAttribute('name'); 
+
+            if (root_title != ""){
+              root_title +=":";
+            }
+	    
+            title = root_title+title;	
+            if (title.length > 50){
+               title = title.substring(0,20)+" ... "+title.substr(title.length-35,35);
+             }
+  
+            berryElement.appendChild(document.createTextNode(title));
+            berryElement.setAttribute("class","berryitem");
+            list.appendChild(berryElement);
+            height +=18;
+          } 
+      	   
+        oldHeight = berryBasket.style.height;
+        oldWidth = berryBasket.style.width;
+        oldBg = berryBasket.style.background; 
+        berryBasket.style.height = height;
+        berryBasket.style.width = width;
+        berryBasket.style.background ='url("interfaces/default/images/kete2.png") 0 0 repeat';
+        berryBasket.style.cursor = "default";         
+        berryBasket.className = "show";
+        div.appendChild(list); 	
+        berries.appendChild(div);  
+        berries.style.height = height - 40;
+
+        var links = document.createElement('div');
+        var hideView = document.createElement('a');
+        var fullView = document.createElement('a');
+        links.appendChild(hideView);
+        links.appendChild(fullView);
+        basketHandle.appendChild(links);
+        hideView.appendChild(document.createTextNode("Hide"));
+        fullView.appendChild(document.createTextNode("Full View"));
+        hideView.setAttribute("id","hideview");
+        fullView.setAttribute("href","?a=g&amp;sa=berry&amp;c=&amp;s=DisplayList&amp;rt=r");
+        fullView.setAttribute("class","fullview");
+
+        }
+
+      function hideBasket() {
+          var i = 0;
+          var berryBasket  = YAHOO.util.Dom.get('berrybasket');  
+          var basketHandle  = YAHOO.util.Dom.get('baskethandle'); 
+          var berries = YAHOO.util.Dom.get('berries'); 
+          berryBasket.style.height = oldHeight;
+          berryBasket.style.width = oldWidth;
+          berryBasket.style.background = oldBg;
+          berryBasket.style.cursor = "pointer";
+          berryBasket.className = "hide";
+
+          while (berries.hasChildNodes()) {
+		berries.removeChild(berries.firstChild);
+	}
+         
+        while (basketHandle.hasChildNodes()) {
+		basketHandle.removeChild(basketHandle.firstChild);
+	}
+         
+        updateBerryImages();
+      }    
+
+
+     function addBerry(el){
+      var  addurl = "?a=pr&amp;rt=r&amp;ro=1&amp;s=AddItem&amp;c=&amp;s1.id=2&amp;o=XML&amp;s1.item=" + el.id;	   
+      var addSuccess = function(o){ 
+ 		 var result = o.responseXML;
+                 var items = result.getElementsByTagName('item');
+                 if (items.length &gt; 0){
+                    var item = items[0];
+                    var berrybasket = YAHOO.util.Dom.get('berrybasket');
+        	    var berries = YAHOO.util.Dom.get('berries');
+                    berryList[berryList.length]= item;   
+                    var parent =el.parentNode;
+                    if (parent == null) return;     
+                    parent.removeChild(el);
+               
+                     var itemID = item.getAttribute('collection')+":"+item.getAttribute('name'); 
+                    if (parent !=null  &amp;&amp; parent.id == "documentberries"){
+                         var root = YAHOO.util.Dom.get(itemID+":root");
+                         var section = YAHOO.util.Dom.get(itemID+":section");
+                         if(root!=null  &amp;&amp; root.id.indexOf(itemID) !=-1){
+                             parent.removeChild(root);
+                          }
+     
+	                  if(section!=null  &amp;&amp; section.id.indexOf(itemID) !=-1){
+                             parent.removeChild(section);
+        	          }                                                
+                     }
+
+                    if (!YAHOO.util.Dom.get('hideview') &amp;&amp;  berryList.length &lt; 13){
+                      while (berries.hasChildNodes()) {
+       	                   berries.removeChild(berries.firstChild);
+	                }
+                        
+                     for (var i =0; i &lt; berryList.length; i++ ){
+                             var img = document.createElement('img');
+                              img.src = 'interfaces/default/images/berry3.png';
+                              img.height = 15;
+                              img.width = 15;
+                              img.border = 0;              
+                              berries.appendChild(img);
+                       }
+      	            
+                                                     
+	          }
+                 else{
+           
+                  if (YAHOO.util.Dom.get('hideview')){
+                        var berryBasket  = YAHOO.util.Dom.get('berrybasket');
+                        var berries  = YAHOO.util.Dom.get('berries');
+                        var doclist = YAHOO.util.Dom.get('doclist'); 
+                        var tid = el.id;                                  
+                        var berryItem; 
+                        var berryElement = document.createElement('li');
+                         for (var i in berryList){
+                             berryItem = berryList[i];
+                             var id = berryItem.getAttribute('collection')+":"+berryItem.getAttribute('name');
+                             if (id == tid){
+                               var title = berryItem.getAttribute('title');
+                               var root_title = berryItem.getAttribute('root_title');  
+                                if (root_title != ""){
+                                      root_title +=":";
+                                     }
+	    
+                                title = root_title+title;	
+                                if (title.length > 50){
+                                   title = title.substring(0,20)+" ... "+title.substr(title.length-35,35);
+                                }
+            
+                               berryElement.appendChild(document.createTextNode(title));
+                               berryElement.setAttribute("class","berryitem");
+                               doclist.appendChild(berryElement);
+                               var heightStr =  berryBasket.style.height+"";
+                               var height =parseInt(heightStr.substring(0,heightStr.length-2)) +18;                             
+                               berryBasket.style.height = height;
+                               berries.style.height = height;
+                               break;
+                            }
+                         }
+                             
+                      }
+                    
+                 }
+               }
+                                       
+             }
+
+           var addFailure = function(o){ }
+
+           var addcallback = {
+        	   success:addSuccess,
+     	           failure:addFailure
+                }
+
+            YAHOO.util.Connect.asyncRequest(request_type , addurl , addcallback);    
+
+         }
+
+  
+      
+     YAHOO.util.Event.addListener(window,'load', checkout); 
+     YAHOO.util.Event.addListener(window,'click', basketUpdate); 
+      </xsl:text>
+    </script>
+  </xsl:template>
+
+  <xsl:template name="berryStyleSheet">
+    <link rel="stylesheet" href="interfaces/default/style/berry.css" type="text/css"/>  
+  </xsl:template>
+  
+</xsl:stylesheet>
Index: /greenstone3/trunk/web/interfaces/default/transform/classifier.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/default/transform/classifier.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/transform/classifier.xsl	(revision 14125)
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+  
+  <xsl:include href="style.xsl"/>
+  <xsl:include href="classifiertools.xsl"/>
+  <xsl:include href="berrytools.xsl"/>
+
+  <xsl:output method="html"/>  
+  <xsl:variable name="berrybasketswitch"><xsl:value-of select="/page/pageRequest/paramList/param[@name='berrybasket']/@value"/></xsl:variable> 
+
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'gsdl')"/>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle">
+    <!--<xsl:if test="$berryBaskets = 'true'">-->
+    <xsl:if test="$berrybasketswitch = 'on'">
+      <xsl:call-template name="berryStyleSheet"/>  
+      <xsl:call-template name="js-library"/>
+    </xsl:if>
+  </xsl:template>
+
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName"><xsl:value-of select="/page/pageRequest/paramList/param[@name='c']/@value"/></xsl:variable>
+    <xsl:variable name="serviceName"><xsl:value-of select="service/@name"/></xsl:variable>
+    <xsl:call-template name="standardPageBanner">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+
+    <xsl:call-template name="navigationBar">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>      
+ 
+    <div id="content">
+      <xsl:apply-templates select="service/classifierList">
+        <xsl:with-param name="collName" select="$collName"/>
+        <xsl:with-param name="serviceName" select="$serviceName"/>
+      </xsl:apply-templates>
+      
+    <!--<xsl:if test="$berryBaskets = 'true'">-->
+    <xsl:if test="$berrybasketswitch = 'on'">
+      <xsl:call-template name="berrybasket" />
+    </xsl:if>  
+    <xsl:apply-templates select="classifier">
+      <xsl:with-param name="collName" select="$collName"/>
+      <xsl:with-param name="serviceName" select="$serviceName"/>
+    </xsl:apply-templates>
+    </div>
+  </xsl:template>
+  
+  <xsl:template match="classifierList">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+    <xsl:variable name="selected" select="/page/pageResponse/classifier/@name"/>
+   <ul id="classifierlist">
+	<xsl:for-each select="classifier">
+	  <xsl:choose>
+	    <xsl:when test="@name=$selected">
+	         <li id="activeclassifier"><xsl:value-of select="displayItem[@name='name']"/></li>
+	    </xsl:when>
+	    <xsl:otherwise>
+	      <li><a href="{$library_name}?a=b&amp;rt=r&amp;s={$serviceName}&amp;c={$collName}&amp;cl={@name}"><xsl:value-of select="displayItem[@name='name']"/></a></li></xsl:otherwise></xsl:choose>
+         
+ 	</xsl:for-each>
+    </ul>
+   </xsl:template>
+
+</xsl:stylesheet>
+
+
+
+
+
+
Index: /greenstone3/trunk/web/interfaces/default/transform/classifiertools.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/default/transform/classifiertools.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/transform/classifiertools.xsl	(revision 14125)
@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+ 
+  <xsl:template match="classifier">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+    <div id="classifiers">
+    <xsl:variable name="cl_name"><xsl:value-of select="@name"/></xsl:variable>
+    <xsl:choose>
+      <xsl:when test="/page/pageResponse/service/classifierList/classifier[@name=$cl_name]/@horizontalAtTop">
+	<xsl:apply-templates select="." mode="horizontal-at-top">
+	  <xsl:with-param name="collName" select="$collName"/>
+	  <xsl:with-param name="serviceName" select="$serviceName"/>
+	</xsl:apply-templates>
+      </xsl:when>
+      <xsl:otherwise>
+	<xsl:apply-templates select="." mode="default">
+	  <xsl:with-param name="collName" select="$collName"/>
+	  <xsl:with-param name="serviceName" select="$serviceName"/>
+	</xsl:apply-templates>
+      </xsl:otherwise>
+    </xsl:choose>
+   </div>
+  </xsl:template>
+  
+
+  <xsl:template match="classifier" mode="horizontal-at-top">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+    <xsl:choose>
+      <xsl:when test="classifierNode">
+      <ul id="classifiernodelist-horizontal">
+	<xsl:for-each select='classifierNode'>
+	  <xsl:apply-templates select='.' mode="horizontal"><xsl:with-param name='collName' select='$collName'/><xsl:with-param name='serviceName' select='$serviceName'/></xsl:apply-templates>
+	</xsl:for-each>
+	</ul>
+	<ul id="childrenlist">
+	  <li>
+            <table><tr>
+	    <xsl:for-each select='classifierNode'>
+	      <xsl:apply-templates select='.' mode='process-all-children'><xsl:with-param name='collName' select='$collName'/><xsl:with-param name='serviceName' select='$serviceName'/></xsl:apply-templates>
+	    </xsl:for-each>
+             </tr></table>
+	  </li>
+	</ul>
+	</xsl:when>
+      <xsl:otherwise>
+	<!-- there were no classifier nodes -->
+	<ul id="childrenlist">
+          <xsl:for-each select='documentNode'>
+	    <li><table><tr><xsl:call-template name="documentNodeWrapper">
+		<xsl:with-param name='collName' select='$collName'/>
+		<xsl:with-param name='serviceName' select='$serviceName'/>
+	      </xsl:call-template></tr></table></li>
+	  </xsl:for-each>
+	</ul>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="classifier" mode="default"> <!-- the default -->
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+    <ul id="classifiernodelist">
+      <xsl:call-template name="processNodeChildren">
+	<xsl:with-param name='collName' select='$collName'/>
+	<xsl:with-param name='serviceName' select='$serviceName'/>
+      </xsl:call-template>
+    </ul>
+  </xsl:template>
+  
+  <!-- this is a wrapper node, which the interface can use to add stuff into the query results that isn't part of and doesn't depend on the documentNode template which may come from the collection -->
+  <xsl:template name="documentNodeWrapper">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/> 
+    <xsl:variable name="berrybasketswitch"><xsl:value-of select="/page/pageRequest/paramList/param[@name='berrybasket']/@value"/></xsl:variable> 
+    <!--<xsl:if test="$berryBaskets = 'true'">-->
+    <xsl:if test="$berrybasketswitch = 'on'">
+      <xsl:call-template name="addBerry">
+	<xsl:with-param name="collName" select="$collName"/>
+      </xsl:call-template> 
+    </xsl:if>
+    <xsl:apply-templates select=".">
+      <xsl:with-param name="collName" select="$collName"/>
+      <xsl:with-param name="serviceName" select="$serviceName"/>
+    </xsl:apply-templates>
+  </xsl:template>
+
+  <xsl:template match="documentNode">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+    <a href="{$library_name}?a=d&amp;c={$collName}&amp;d={@nodeID}&amp;dt={@docType}&amp;p.a=b&amp;p.s={$serviceName}"><xsl:apply-templates select="." mode="displayNodeIcon"/></a><xsl:value-of disable-output-escaping="yes"  select="metadataList/metadata[@name='Title']"/>
+  </xsl:template>
+
+  
+  
+  <!-- icon + title template-->
+  <xsl:template match="classifierNode">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+      <a><xsl:attribute name='href'><xsl:value-of select='$library_name'/>?a=b&amp;rt=r&amp;s=<xsl:value-of select='$serviceName'/>&amp;c=<xsl:value-of select='$collName'/>&amp;cl=<xsl:value-of select='@nodeID'/><xsl:if test="classifierNode|documentNode">.pr</xsl:if></xsl:attribute><xsl:call-template name="bookshelfimg"/></a><xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name='Title']"/>
+  </xsl:template>
+  
+  <!-- the title is a link: an alternative template -->
+  <xsl:template match="classifierNode" mode="horizontal">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+    <li><xsl:choose>
+      <xsl:when test="classifierNode|documentNode"><b><xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name='Title']"/><xsl:text> </xsl:text></b></xsl:when>
+      <xsl:otherwise>
+<a><xsl:attribute name='href'><xsl:value-of select='$library_name'/>?a=b&amp;rt=r&amp;s=<xsl:value-of select='$serviceName'/>&amp;c=<xsl:value-of select='$collName'/>&amp;cl=<xsl:value-of select='@nodeID'/></xsl:attribute><xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name='Title']"/></a><xsl:text> </xsl:text></xsl:otherwise>
+    </xsl:choose>
+    </li>
+  </xsl:template>
+  
+
+  <!-- processing for the recursive bit -->
+  <xsl:template match="classifierNode" mode="process-all-children">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+      <xsl:call-template name="processNodeChildren">
+	  <xsl:with-param name='collName' select='$collName'/>
+	  <xsl:with-param name='serviceName' select='$serviceName'/>
+      </xsl:call-template>
+   </xsl:template>
+  
+  <xsl:template name="processNodeChildren">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+    <xsl:for-each select='classifierNode|documentNode'>
+      <xsl:choose><xsl:when test="name()='documentNode'">
+	 <li><table><tr>
+	    <xsl:call-template name="documentNodeWrapper">
+	      <xsl:with-param name='collName' select='$collName'/>
+	      <xsl:with-param name='serviceName' select='$serviceName'/>
+	    </xsl:call-template>
+             </tr></table>
+	  </li>
+	</xsl:when>
+	<xsl:otherwise>
+	  <li><table><tr>
+	    <xsl:apply-templates select='.'>
+	      <xsl:with-param name='collName' select='$collName'/>
+	      <xsl:with-param name='serviceName' select='$serviceName'/>
+	    </xsl:apply-templates>
+             </tr></table>
+	  </li>
+	  <xsl:if test="child::classifierNode or child::documentNode">
+	    <!--recurse into the children-->
+	    <li><ul class="childrenlist">
+	      <xsl:apply-templates select='.' mode='process-all-children'>
+		<xsl:with-param name='collName' select='$collName'/>
+		<xsl:with-param name='serviceName' select='$serviceName'/>
+	      </xsl:apply-templates>
+                </ul>
+	    </li>
+	  </xsl:if>
+	</xsl:otherwise>
+      </xsl:choose>
+    </xsl:for-each>
+  </xsl:template>
+</xsl:stylesheet>
Index: /greenstone3/trunk/web/interfaces/default/transform/config_format.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/default/transform/config_format.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/transform/config_format.xsl	(revision 14125)
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:xslt="output.xsl"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat"
+  extension-element-prefixes="java">
+  
+  <xsl:output method="xml"/>
+  <xsl:namespace-alias
+    stylesheet-prefix="xslt" result-prefix="xsl"/>
+
+  <xsl:template match="format">
+    <format>
+      <xsl:apply-templates/>
+    </format>
+  </xsl:template>
+  
+  <xsl:template match="gsf:template">
+    <xslt:template>
+      <xsl:copy-of select="@*"/>
+      <xsl:attribute name="priority">2</xsl:attribute> 
+      <xsl:if test=".//gsf:link">
+	<xslt:param name="serviceName"/>
+	<xslt:param name="collName"/>
+      </xsl:if>
+      <xsl:apply-templates/>
+    </xslt:template>
+  </xsl:template>
+  
+  <xsl:template match="gsf:link">
+    <xsl:choose>
+      <xsl:when test="@type='classifier'">
+	<a><xslt:attribute name='href'><xslt:value-of select='$library_name'/>?a=b&amp;rt=r&amp;s=<xslt:value-of select='$serviceName'/>&amp;c=<xslt:value-of select='$collName'/>&amp;cl=<xslt:value-of select='@nodeID'/><xslt:if test="classifierNode|documentNode">.pr</xslt:if><xslt:if test="parent::node()[@orientation='horizontal']">&amp;sib=1</xslt:if></xslt:attribute>
+	  <xsl:apply-templates/>
+	</a>
+      </xsl:when>
+      <xsl:otherwise> <!-- a document link -->
+	<xslt:variable name="bookswitch"><xslt:value-of select="/page/pageRequest/paramList/param[@name='book']/@value"/></xslt:variable>
+	<xslt:choose>
+    		<xslt:when test="$bookswitch = 'on' or $bookswitch = 'flashxml'">
+		        <a><xslt:attribute name="href"><xslt:value-of select='$library_name'/>?a=d&amp;ed=1&amp;book=on&amp;c=<xslt:value-of select='$collName'/>&amp;d=<xslt:value-of select='@nodeID'/>&amp;dt=<xslt:value-of select='@docType'/><xslt:if test="@nodeType='leaf'">&amp;sib=1</xslt:if>&amp;p.a=<xslt:value-of select="/page/pageRequest/@action"/>&amp;p.sa=<xsl:value-of select="/page/pageRequest/@subaction"/>&amp;p.s=<xslt:value-of select="$serviceName"/></xslt:attribute><xsl:apply-templates/></a>
+		</xslt:when>
+		<xslt:otherwise>
+		       <a><xslt:attribute name="href"><xslt:value-of select='$library_name'/>?a=d&amp;book=off&amp;c=<xslt:value-of select='$collName'/>&amp;d=<xslt:value-of select='@nodeID'/>&amp;dt=<xslt:value-of select='@docType'/><xslt:if test="@nodeType='leaf'">&amp;sib=1</xslt:if>&amp;p.a=<xslt:value-of select="/page/pageRequest/@action"/>&amp;p.sa=<xsl:value-of select="/page/pageRequest/@subaction"/>&amp;p.s=<xslt:value-of select="$serviceName"/></xslt:attribute><xsl:apply-templates/></a>
+		</xslt:otherwise>
+	</xslt:choose>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="gsf:icon">
+    <xsl:choose>
+      <xsl:when test="@type='classifier'">
+	<xslt:call-template name="bookshelfimg"/>
+      </xsl:when>
+      <xsl:otherwise>
+	<xslt:apply-templates select="." mode="displayNodeIcon"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+  
+  <xsl:template match="gsf:metadata[@format]">
+    <xslt:value-of disable-output-escaping="yes"><xsl:attribute name="select">java:org.greenstone.gsdl3.util.XSLTUtil.<xsl:value-of select="@format"/>(metadataList/metadata[@name='<xsl:apply-templates select="." mode="get-metadata-name"/>'], /page/@lang )</xsl:attribute></xslt:value-of>
+  </xsl:template>
+
+  <xsl:template match="gsf:metadata">
+    <xslt:value-of disable-output-escaping="yes"><xsl:attribute name="select">metadataList/metadata[@name='<xsl:apply-templates select="." mode="get-metadata-name"/>']</xsl:attribute></xslt:value-of>
+  </xsl:template>
+
+  <xsl:template match="gsf:metadata" mode="get-metadata-name">
+    <xsl:if test="@multiple='true'">all_</xsl:if><xsl:if test='@select'><xsl:value-of select='@select'/>_</xsl:if><xsl:if test="@separator">*<xsl:value-of select='@separator'/>*_</xsl:if><xsl:value-of select="@name"/>
+  </xsl:template>
+  
+  <xsl:template match="gsf:metadata-old">
+    <xslt:value-of disable-output-escaping="yes"><xsl:attribute name="select">metadataList/metadata[@name="<xsl:choose><xsl:when test="@select='parent'">parent_</xsl:when><xsl:when test="@select='root'">root_</xsl:when><xsl:when test="@select='ancestors'">ancestors'<xsl:value-of select='@separator'/>'_</xsl:when><xsl:when test="@select='siblings'">siblings_'<xsl:value-of select='@separator'/>'_</xsl:when></xsl:choose><xsl:value-of select="@name"/>"]</xsl:attribute></xslt:value-of>
+  </xsl:template>
+  
+  <xsl:template match="gsf:text">
+    <xslt:apply-templates select="nodeContent"/>
+  </xsl:template>
+  
+  <xsl:template match="gsf:choose-metadata">
+    <xslt:choose>
+      <xsl:for-each select="gsf:metadata">
+	<xslt:when><xsl:attribute name="test">metadataList/metadata[@name='<xsl:apply-templates select="." mode="get-metadata-name"/>']</xsl:attribute>
+	  <xsl:apply-templates select="."/>
+	</xslt:when>
+      </xsl:for-each>
+      <xsl:if test="gsf:default">
+	<xslt:otherwise><xsl:apply-templates/></xslt:otherwise>
+      </xsl:if>
+    </xslt:choose>
+  </xsl:template>
+  
+  <xsl:template match="gsf:switch">
+    <xsl:variable name="meta-name"><xsl:apply-templates select="gsf:metadata" mode="get-metadata-name"/></xsl:variable>
+    <xslt:variable name="meta"><xsl:choose><xsl:when test="@preprocess"><xslt:value-of select="util:{@preprocess}(metadataList/metadata[@name='{$meta-name}'])"/></xsl:when><xsl:otherwise><xslt:value-of select="metadataList/metadata[@name='{$meta-name}']"/></xsl:otherwise></xsl:choose></xslt:variable>
+    <xslt:choose>
+      <xsl:for-each select="gsf:when">
+	<xslt:when test="util:{@test}($meta, '{@test-value}')">
+	  <xsl:apply-templates/>
+	</xslt:when>
+      </xsl:for-each>
+      <xsl:if test="gsf:otherwise">
+	<xslt:otherwise>
+	  <xsl:apply-templates select="gsf:otherwise/node()"/>
+	</xslt:otherwise>
+      </xsl:if>
+    </xslt:choose>
+  </xsl:template>
+  
+  <xsl:template match="*">
+    <xsl:copy>
+      <xsl:copy-of select="@*"/>
+      <xsl:apply-templates/>
+    </xsl:copy>
+  </xsl:template>
+
+</xsl:stylesheet>
+
+
Index: /greenstone3/trunk/web/interfaces/default/transform/document.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/default/transform/document.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/transform/document.xsl	(revision 14125)
@@ -0,0 +1,576 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util gsf">
+
+  <xsl:include href="style.xsl"/>
+  <xsl:include href="service-params.xsl"/>
+  <xsl:include href="berrytools.xsl"/>
+
+  <xsl:output method="html"/>
+   <xsl:variable name="berrybasketswitch"><xsl:value-of select="/page/pageRequest/paramList/param[@name='berrybasket']/@value"/></xsl:variable> 
+   <xsl:variable name="bookswitch"><xsl:value-of select="/page/pageRequest/paramList/param[@name='book']/@value"/></xsl:variable>
+  
+  <xsl:template name="pageTitle">
+    <xsl:variable name="docID" select="/page/pageResponse/document/@selectedNode"/>
+    <xsl:for-each select='/page/pageResponse/document/descendant::documentNode[@nodeID=$docID]/ancestor-or-self::documentNode'><xsl:if test='position()!=1'>::</xsl:if><xsl:value-of select="metadataList/metadata[@name='Title']"/></xsl:for-each>
+  </xsl:template>
+
+  <!-- this is hard coded for GATE, should somehow do it dynamically-->
+  <xsl:template name="pageStyle">
+    <style type="text/css">
+      <xsl:text disable-output-escaping="yes">
+	span.Location {  display:inline; color : red }
+	span.Person {  display:inline; color : green }
+	span.Organization {  display:inline; color : yellow }
+	span.Date {  display:inline; color : blue }
+	span.query_term {display: inline; background-color : yellow }
+      </xsl:text>
+    </style>
+     <!--TODO: add berry basket switch-->
+ <!--<xsl:if test="$berryBaskets = 'true'">-->
+    <xsl:if test="$berrybasketswitch = 'on'">
+     <xsl:call-template name="berryStyleSheet"/>  
+     <xsl:call-template name="js-library"/>
+    </xsl:if>
+  </xsl:template>
+  
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName"><xsl:value-of select="/page/pageRequest/paramList/param[@name='c']/@value"/></xsl:variable>
+    <xsl:choose>
+      <xsl:when test="$bookswitch = 'on' or $bookswitch = 'off'">
+        <xsl:call-template name="standardPageBanner">
+           <xsl:with-param name="collName" select="$collName"/>
+        </xsl:call-template>
+        <xsl:call-template name="navigationBar">
+           <xsl:with-param name="collName" select="$collName"/>
+        </xsl:call-template>
+  
+        <!--<xsl:if test="$berryBaskets = 'true'">-->
+        <xsl:if test="$berrybasketswitch = 'on'">
+          <xsl:call-template name="documentBerryBasket">
+             <xsl:with-param name="collName" select="$collName"/>
+             <xsl:with-param name="selectedNode" select="/page/pageResponse/document/@selectedNode"/>
+             <xsl:with-param name="rootNode" select="/page/pageResponse/document/documentNode[@nodeType='root']/@nodeID"/>
+             <xsl:with-param name="docType" select="/page/pageResponse/document/@docType"/>
+          </xsl:call-template>
+        </xsl:if>
+      </xsl:when>
+   </xsl:choose>	
+
+  <!-- display the document -->
+    <xsl:if test="$bookswitch != 'flashxml'">
+       <xsl:text disable-output-escaping="yes">&lt;div id="content"&gt;</xsl:text>
+    </xsl:if>
+    <xsl:apply-templates select="document">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:apply-templates>
+    <xsl:if test="$bookswitch != 'flashxml'">
+	<xsl:text disable-output-escaping="yes">&lt;/div&gt;</xsl:text>
+    </xsl:if>
+  </xsl:template>
+	
+  <xsl:template match="document">
+   <xsl:param name="collName"/>
+  
+   <xsl:if test="$bookswitch = 'flashxml'">
+			<xsl:call-template name="xmldocumentContentPeeling">
+				<xsl:with-param name="collName" select="$collName"/>
+			</xsl:call-template>
+		</xsl:if>
+   
+   <xsl:if test="$bookswitch = 'off'">
+    <xsl:call-template name="documentHeading">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+  
+    <xsl:call-template name="documentArrows">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>         
+    <xsl:call-template name="documentContent">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+    <xsl:call-template name="documentArrows">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>   
+   </xsl:if>
+   <xsl:if test="$bookswitch = 'on'">
+			<xsl:call-template name="documentHeading">
+				<xsl:with-param name="collName" select="$collName"/>
+			</xsl:call-template>
+			<div id="bookdiv"></div>
+			<script type="text/javascript">
+				<xsl:text disable-output-escaping="yes">
+					var doc_url = document.URL; 
+					doc_url = doc_url.replace(/(&amp;|\?)book=[a-z]+/gi,'');
+					doc_url += '&amp;book=flashxml';
+
+					// var src_image = "http://kia.cs.waikato.ac.nz:8080/greenstone3/sites/localsite/collect/gs2mgdemo/index/assoc/HASH49aa.dir/cover.jpg"
+					//var doc_url = "/greenstone3/library?a=d&amp;c=gs2mgdemo&amp;d=HASH49aab56062938fbe2ff7f1&amp;dt=hierarchy&amp;p.a=b&amp;p.s=ClassifierBrowse&amp;ed=1";
+
+					var flash_plug_html = ""
+					flash_plug_html += '&lt;OBJECT align="middle" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" \n';
+					flash_plug_html += '  codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0" \n';
+					flash_plug_html += '  height="100%" id="Book" swLiveConnect="true" \n';
+					flash_plug_html += '  width="100%"&gt;\n';
+					flash_plug_html += '    &lt;PARAM name="allowScriptAccess" value="always" /&gt;\n';
+					flash_plug_html += '    &lt;PARAM name="movie" value="Book.swf';
+					flash_plug_html += '?src_image=' + escape(img_cover);
+					flash_plug_html += '&amp;doc_url=' + escape(doc_url)
+					flash_plug_html += '" /&gt;\n';
+					flash_plug_html += '    &lt;PARAM name="quality" value="high" /&gt;\n';
+					flash_plug_html += '    &lt;PARAM name="bgcolor" value="#FFFFFF" /&gt;\n';
+					flash_plug_html += '    &lt;EMBED align="middle" \n';
+					flash_plug_html += '      allowScriptAccess="always" swLiveConnect="true" \n';
+					flash_plug_html += '      bgcolor="#FFFFFF" height="100%" name="Book" \n';
+					flash_plug_html += '      pluginspage="http://www.macromedia.com/go/getflashplayer" \n';
+					flash_plug_html += '      quality="high" \n';
+					flash_plug_html += '      src="Book.swf';
+					flash_plug_html += '?src_image=' + escape(img_cover);
+					flash_plug_html += '&amp;doc_url=' + escape(doc_url);
+					flash_plug_html += '"\n'; 
+					flash_plug_html += '      type="application/x-shockwave-flash" width="100%" /&gt;\n';
+					flash_plug_html += '&lt;/OBJECT&gt;\n';
+					var flash_div = document.getElementById("bookdiv");
+					flash_div.innerHTML = flash_plug_html;
+				</xsl:text>
+			</script>
+		</xsl:if>    
+ </xsl:template>
+
+  <xsl:template name="documentHeading">
+    <xsl:param name="collName"/>
+    <xsl:variable name="doCoverImage" select="/page/pageResponse/format/gsf:option[@name='coverImages']/@value"/>
+    <xsl:variable name="doTOC" select="/page/pageResponse/format/gsf:option[@name='documentTOC']/@value"/>
+    <xsl:variable name="p.a" select="/page/pageRequest/paramList/param[@name='p.a']/@value"/>
+    <xsl:variable name="p.sa" select="/page/pageRequest/paramList/param[@name='p.sa']/@value"/>
+    <xsl:variable name="p.s" select="/page/pageRequest/paramList/param[@name='p.s']/@value"/>
+    <xsl:variable name="p.c"><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name='p.c']"><xsl:value-of select="/page/pageRequest/paramList/param[@name='p.c']/@value"/></xsl:when><xsl:otherwise><xsl:value-of select="$collName"/></xsl:otherwise></xsl:choose></xsl:variable>
+   <div id="documentheading">
+	  <a href="{$library_name}?a={$p.a}&amp;sa={$p.sa}&amp;s={$p.s}&amp;c={$p.c}&amp;rt=rd"><xsl:call-template name="openbookimg"><xsl:with-param name="title">Close this book and return to search/browse</xsl:with-param>
+	  </xsl:call-template></a>
+	     <xsl:choose><xsl:when test="@docType='simple'"><xsl:value-of select="metadataList/metadata[@name='Title']" disable-output-escaping="yes"/></xsl:when><xsl:otherwise><xsl:value-of select="documentNode/metadataList/metadata[@name='Title']" disable-output-escaping="yes"/></xsl:otherwise></xsl:choose>
+  </div>
+  
+ <div id="docheadwrapper">
+  <div id="documentinfo">
+    
+  <xsl:choose>
+    <xsl:when test="$bookswitch = 'on'">
+    	<xsl:if test="string($doCoverImage) != 'false' and (@docType='paged' or @docType='hierarchy')">
+         <div id="headingimage">
+          <xsl:call-template name="coverImage"/> 
+         </div>
+        </xsl:if>
+    </xsl:when>
+    <xsl:otherwise>
+    	<xsl:if test="string($doCoverImage) != 'false' and (@docType='paged' or @docType='hierarchy')">
+       	  <div id="headingimage">
+             <xsl:call-template name="coverImage"/> 
+          </div>
+        </xsl:if>
+     
+        <ul id="docbuttons" >
+         <xsl:call-template name="documentButtons">
+	   <xsl:with-param name="collName" select="$collName"/>
+         </xsl:call-template>
+       </ul>
+     </xsl:otherwise>
+  </xsl:choose>     
+  </div>
+    <!--<div><xsl:call-template name="enrichServices">
+	   <xsl:with-param name="collName" select="$collName"/>
+	  </xsl:call-template></div>-->
+   <xsl:if test="$bookswitch = 'off'">
+    <xsl:if test="string($doTOC) != 'false'">
+       <div id="toc">
+	 <xsl:call-template name="TOC">
+	   <xsl:with-param name="collName" select="$collName"/>
+	 </xsl:call-template>
+      </div>
+    </xsl:if>
+  </xsl:if>  
+ </div>
+ </xsl:template>
+
+  <xsl:template name="coverImage">
+  <xsl:choose>
+			<xsl:when test="$bookswitch = 'on'">
+				<script type="text/javascript">
+					<xsl:text disable-output-escaping="yes">var img_cover = '</xsl:text><xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/>/index/assoc/<xsl:value-of select="metadataList/metadata[@name='archivedir']"/>/cover.jpg<xsl:text disable-output-escaping="yes">';</xsl:text>
+				</script>
+			</xsl:when>
+			<xsl:otherwise>
+    				<img><xsl:attribute name='src'><xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/>/index/assoc/<xsl:value-of select="metadataList/metadata[@name='archivedir']"/>/cover.jpg</xsl:attribute></img>
+			</xsl:otherwise>
+		</xsl:choose>
+  </xsl:template>
+
+  <xsl:template name="documentButtons">
+    <xsl:param name="collName"/>
+    <xsl:variable name="docID" select="/page/pageRequest/paramList/param[@name='d']/@value"/>
+    <xsl:variable name="sib" select="/page/pageRequest/paramList/param[@name='sib']/@value"/>
+    <xsl:variable name="ec" select="/page/pageRequest/paramList/param[@name='ec']/@value"/>
+    <xsl:variable name="ed" select="/page/pageRequest/paramList/param[@name='ed']/@value"/>
+    
+   
+      <!-- expand document -->
+      <!-- this doesn't work with MG so comment it out for now -->
+      
+   <xsl:if test="@docType = 'hierarchy' or @docType = 'paged'">
+     <li>
+        <xsl:choose><xsl:when test="string($ed)='1'">
+	      <a href="{$library_name}?a=d&amp;d={$docID}&amp;c={$collName}&amp;sib={$sib}&amp;ed=0"><xsl:attribute name="title"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'doc.contract_doc_tip')"/></xsl:attribute>
+		  <xsl:value-of disable-output-escaping='yes' select="util:getInterfaceText($interface_name, /page/@lang, 'doc.contract_doc_b')"/>
+	      </a>
+	    </xsl:when>
+	    <xsl:otherwise>
+	  <a href="{$library_name}?a=d&amp;d={$docID}&amp;c={$collName}&amp;sib={$sib}&amp;ed=1"><xsl:attribute name="title"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'doc.expand_doc_tip')"/></xsl:attribute>
+	     <xsl:value-of disable-output-escaping='yes' select="util:getInterfaceText($interface_name, /page/@lang, 'doc.expand_doc_b')"/>
+	  </a>
+	    </xsl:otherwise>
+	  </xsl:choose>
+      	</li>
+      </xsl:if> 
+      
+      <!-- expand contents -->
+      <xsl:if test="@docType = 'hierarchy' and string(/page/pageResponse/format/gsf:option[@name='documentTOC']/@value) != 'false'">
+      <li>
+          <xsl:choose><xsl:when test="string($ec)='1'">
+	      <a href="{$library_name}?a=d&amp;d={$docID}&amp;c={$collName}&amp;sib={$sib}&amp;ec=0"><xsl:attribute name="title"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'doc.contract_contents_tip')"/></xsl:attribute>
+		<xsl:value-of disable-output-escaping='yes' select="util:getInterfaceText($interface_name, /page/@lang, 'doc.contract_contents_b')"/></a>
+	    </xsl:when>
+	    <xsl:otherwise>
+	      <a  href="{$library_name}?a=d&amp;d={$docID}&amp;c={$collName}&amp;sib={$sib}&amp;ec=1"><xsl:attribute name="title"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'doc.expand_contents_tip')"/></xsl:attribute>
+		 <xsl:value-of disable-output-escaping='yes' select="util:getInterfaceText($interface_name, /page/@lang, 'doc.expand_contents_b')"/>
+	      </a>
+	    </xsl:otherwise>
+	  </xsl:choose>
+	 </li>
+      </xsl:if>
+
+      <!-- detach page -->
+      <xsl:variable name="paramList" select="/page/pageRequest/paramList"/>
+       <li>
+	  <a target="_blank"><xsl:attribute name="href"><xsl:value-of select="$library_name"/>?a=d&amp;d=<xsl:value-of select="$docID"/>&amp;c=<xsl:value-of select="$collName"/>&amp;sib=<xsl:value-of select="$sib"/>&amp;dt=<xsl:value-of select="$paramList/param[@name='dt']/@value"/>&amp;ec=<xsl:value-of select="$paramList/param[@name='ec']/@value"/>&amp;et=<xsl:value-of select="$paramList/param[@name='et']/@value"/>&amp;p.a=<xsl:value-of select="$paramList/param[@name='p.a']/@value"/>&amp;p.s=<xsl:value-of select="$paramList/param[@name='p.s']/@value"/>&amp;p.sa=<xsl:value-of select="$paramList/param[@name='p.sa']/@value"/></xsl:attribute><xsl:attribute name="title"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'doc.detach_page_tip')"/></xsl:attribute>
+	    <xsl:value-of disable-output-escaping='yes' select="util:getInterfaceText($interface_name, /page/@lang, 'doc.detach_page_b')"/>
+	  </a></li>
+      </xsl:template>
+
+  <xsl:template name="TOC">
+    <xsl:param name="collName"/>
+    <xsl:choose>
+      <xsl:when test="@docType='hierarchy'">
+	<xsl:call-template name="hierarchicalContents">
+	  <xsl:with-param name="collName" select="$collName"/>
+	</xsl:call-template>
+      </xsl:when>
+      <xsl:when test="@docType='paged'">
+	<xsl:call-template name="pagedContents">
+	  <xsl:with-param name="collName" select="$collName"/>
+	</xsl:call-template>
+      </xsl:when>
+    </xsl:choose>
+  </xsl:template>
+    
+  <xsl:template name="hierarchicalContents">
+    <xsl:param name="collName"/>
+    <xsl:variable name="oc" select="/page/pageRequest/paramList/param[@name='oc']/@value"/>
+    <xsl:variable name="d" select="/page/pageRequest/paramList/param[@name='d']/@value"/>
+    <xsl:variable name="sib" select="/page/pageRequest/paramList/param[@name='sib']/@value"/>
+    <xsl:variable name="ec" select="/page/pageRequest/paramList/param[@name='ec']/@value"/>
+    <xsl:variable name="p.s" select="/page/pageRequest/paramList/param[@name='p.s']/@value"/>
+    <xsl:variable name="p.sa" select="/page/pageRequest/paramList/param[@name='p.sa']/@value"/>
+    <xsl:variable name="p.a" select="/page/pageRequest/paramList/param[@name='p.a']/@value"/>
+    <xsl:variable name="p.c"><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name='p.c']"><xsl:value-of select="/page/pageRequest/paramList/param[@name='p.c']/@value"/></xsl:when><xsl:otherwise><xsl:value-of select="$collName"/></xsl:otherwise></xsl:choose></xsl:variable>
+    <xsl:if test="documentNode[@nodeID]">
+      <ul id="tocnodes">
+	<li>
+	    <xsl:choose><xsl:when test="string($oc)='0'">
+		<a href="{$library_name}?a=d&amp;c={$collName}&amp;d={$d}&amp;sib={$sib}&amp;oc=1"><xsl:call-template name="closedfolderimg"><xsl:with-param name="title">open the table of contents</xsl:with-param></xsl:call-template></a>
+	      </xsl:when>
+	      <xsl:otherwise><a href="{$library_name}?a=d&amp;c={$collName}&amp;d={$d}&amp;sib={$sib}&amp;oc=0"><xsl:call-template name="openfolderimg"><xsl:with-param name="title">close the table of contents</xsl:with-param></xsl:call-template></a></xsl:otherwise></xsl:choose>Table of Contents
+	<xsl:if test="string($oc)!='0'">
+           <ul class="tocnode">
+	    <xsl:for-each select="documentNode/documentNode[@nodeID]">
+		  <xsl:apply-templates select='.'><xsl:with-param name="collName" select="$collName"/><xsl:with-param name="ec" select="$ec"/><xsl:with-param name="p.a" select="$p.a"/><xsl:with-param name="p.s" select="$p.s"/><xsl:with-param name="p.sa" select="$p.sa"/><xsl:with-param name="p.c" select="$p.c"/></xsl:apply-templates>
+		</xsl:for-each>
+            </ul>
+	   </xsl:if>
+        </li> 
+      </ul>
+    </xsl:if>
+  </xsl:template>
+  
+  <!-- each icon-title pair is a row in a table. children go in a table in another row -->
+  <xsl:template match="documentNode">
+    <xsl:param name="collName"/>
+    <xsl:param name="ec"/>
+    <xsl:param name="p.a"/>
+    <xsl:param name="p.s"/>
+    <xsl:param name="p.sa"/>
+    <xsl:param name="p.c"/>
+    <!-- Display the appropriate image, depending on the node type -->
+     <li>
+	<a><xsl:attribute name="href"><xsl:value-of select='$library_name'/>?a=d&amp;c=<xsl:value-of select='$collName'/>&amp;d=<xsl:value-of select='@nodeID'/><xsl:if test="documentNode">.pr</xsl:if>&amp;sib=1<xsl:if test="string($ec) = '1'">&amp;ec=1</xsl:if>&amp;p.a=<xsl:value-of select="$p.a"/>&amp;p.sa=<xsl:value-of select="$p.sa"/>&amp;p.s=<xsl:value-of select="$p.s"/>&amp;p.c=<xsl:value-of select="$p.c"/></xsl:attribute>
+	  <xsl:apply-templates select="." mode="displayNodeIcon"/>
+	</a>
+      
+      <!-- Display associated title, bolded if the node has content -->
+	<xsl:choose>
+          <xsl:when test="nodeContent">
+	    <span class="bold"><xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name='Title']"/></span>
+	  </xsl:when>
+	  <xsl:otherwise>
+	    <xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name='Title']"/>
+	  </xsl:otherwise>
+	</xsl:choose>
+    <!-- Apply recursively to the children of this node -->
+    <xsl:if test="documentNode[@nodeID]">
+       <ul class="tocnode"> <xsl:apply-templates select="documentNode[@nodeID]">
+	      <xsl:with-param name="collName" select="$collName"/>
+	      <xsl:with-param name="ec" select="$ec"/>
+	      <xsl:with-param name="p.a" select="$p.a"/><xsl:with-param name="p.s" select="$p.s"/><xsl:with-param name="p.sa" select="$p.sa"/><xsl:with-param name="p.c" select="$p.c"/>
+	      <!--<xsl:with-param name="depth" select="$depth + 1"/>-->
+	    </xsl:apply-templates>
+       </ul>
+     </xsl:if>
+    </li>
+  </xsl:template>
+  
+  <!-- default content is to print the title and content of any documentNodes that have nodeContent -->
+  <xsl:template name="documentContent">
+   <div class="documenttext"> 
+    <xsl:choose>
+      <xsl:when test="@docType='simple'"><xsl:apply-templates select="nodeContent"/></xsl:when>
+      <xsl:otherwise>
+	<xsl:apply-templates select="descendant-or-self::node()/documentNode" mode="content"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </div>
+  </xsl:template>
+  
+  <xsl:template match="documentNode" mode="content">
+    <xsl:if test="nodeContent">
+      <xsl:if test="metadataList/metadata[@name='Title']">
+	<h3><xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name='Title']"/></h3>
+      </xsl:if>
+      <xsl:apply-templates select="nodeContent"/>
+    </xsl:if>
+  </xsl:template>
+
+  <!-- the actual text/content -->
+  <xsl:template match="nodeContent">
+    <p/>
+    <xsl:for-each select="node()">
+      <xsl:choose>
+	<xsl:when test="not(name())">
+		<xsl:value-of select="." disable-output-escaping="yes"/>
+	</xsl:when>
+	<xsl:otherwise><xsl:apply-templates select="."/></xsl:otherwise>
+      </xsl:choose>
+    </xsl:for-each>
+  </xsl:template>
+  
+  <xsl:template name="xmldocumentContentPeeling">
+		<xsl:choose>
+			<xsl:when test="@docType='simple'">
+				<xsl:apply-templates select="nodeContent"/>
+			</xsl:when>
+			<xsl:otherwise>
+				<xsl:call-template name="xmlpeelingContents" />
+			</xsl:otherwise>
+		</xsl:choose>
+	</xsl:template>
+	
+  <xsl:template name="xmlpeelingContents">
+		<xsl:if test="documentNode">
+			<xsl:apply-templates select="documentNode" mode="xmlpeeling" />
+		</xsl:if>
+	</xsl:template>
+
+	<xsl:template match="documentNode" mode="xmlpeeling">
+		<!-- get title -->
+		<xsl:choose>
+			<xsl:when test="nodeContent">
+				<xsl:text disable-output-escaping="yes">
+					&lt;Section&gt;
+					&lt;Description&gt;
+					&lt;Metadata name="Title"&gt;
+				</xsl:text>
+				<xsl:value-of select="normalize-space(metadataList/metadata[@name='Title'])"/>
+				<xsl:text disable-output-escaping="yes">
+					&lt;/Metadata&gt;
+					&lt;/Description&gt;
+				</xsl:text>
+				<xsl:value-of select="normalize-space(nodeContent)" disable-output-escaping="yes"/>
+				<xsl:text disable-output-escaping="yes">&lt;/Sec&gt;</xsl:text>
+			</xsl:when>
+		</xsl:choose>
+
+		<!-- recurse to the children -->
+		<xsl:if test="documentNode">
+			<xsl:apply-templates select="documentNode" mode="xmlpeeling" />
+		</xsl:if>
+
+		<!-- end the section -->
+		<xsl:text disable-output-escaping="yes">
+			&lt;/Section&gt;
+		</xsl:text>
+	</xsl:template>
+  
+  <!-- match any file nodes -->
+  <xsl:template match="file">
+    <xsl:variable name="httpPath" select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/>
+    <xsl:choose>
+      <xsl:when test="util:isImage(@mimeType)">
+	<img src="{$httpPath}/{@href}"/>
+      </xsl:when>
+      <xsl:otherwise>
+	<a href="{$httpPath}/{@href}"><xsl:value-of select="@href"/></a>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+  
+  <!-- match any link nodes -->
+  <xsl:template match="link">
+    <xsl:variable name="collName" select="/page/pageRequest/paramList/param[@name='c']/@value"/> 
+    <xsl:variable name="actionargs">
+      <xsl:choose>
+	<xsl:when test="@type='document'">a=d</xsl:when>
+	<xsl:when test="@type='query'">a=q&amp;s=<xsl:value-of select="@service"/>&amp;rt=rd</xsl:when>
+	<xsl:otherwise>
+	  p
+	</xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="serviceargs">
+      <xsl:for-each select="param">&amp;s1.<xsl:value-of select="@name"/>=<xsl:value-of select="@value"/></xsl:for-each>
+  </xsl:variable>
+    <a href="{$library_name}?{$actionargs}&amp;c={$collName}{$serviceargs}"><xsl:value-of disable-output-escaping="yes" select="."/></a>
+  </xsl:template>
+
+  <!-- match any annotations and make them span elements -->
+  <xsl:template match="annotation">
+    <span class="{@type}"><xsl:value-of disable-output-escaping="yes" select="."/></span>
+  </xsl:template>
+  
+  <!-- paged naviagtion : INCOMPLETE!!-->
+  <xsl:template name="pagedContents">
+    <xsl:param name="collName"/>
+    <xsl:variable name="pos" select="nodeStructureInfo/info[@name='siblingPosition']/@value"/>
+    <xsl:variable name="length" select="nodeStructureInfo/info[@name='numSiblings']/@value"/>
+    <xsl:variable name="children" select="nodeStructureInfo/info[@name='numChildren']/@value"/>
+    <table>
+      <xsl:choose>
+	<xsl:when test="$pos=-1"><!-- a doc -->
+	  <tr valign="top">
+	    <td align="left">
+	    </td>
+	    <td align="center"><center>
+		<b><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'document.pages', $children)"/></b>
+	      </center></td>
+	    <td align="right">
+	      <a href="{$library_name}?a=d&amp;c={$collName}&amp;d={@selectedNode}.fc"><img src="interfaces/default/images/more.gif" border="0" align="absbottom" /></a>
+	    </td>
+	  </tr>
+	</xsl:when>
+	
+	<xsl:otherwise> <!-- an internal node -->	  
+	  <tr valign="top">
+	    <td align="left">
+	      <xsl:if test=" not ( $pos = 1 )">
+		<a href="{$library_name}?a=d&amp;c={$collName}&amp;d={@selectedNode}.ps"><img src="interfaces/default/images/less.gif" border="0" align="absbottom" /></a>
+	      </xsl:if>
+	    </td>
+	    <td align="center"><center>
+		<b><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'document.pageof', concat($pos, ';', $length))"/></b>
+	      </center></td>
+	    <td align="right">
+	      <xsl:if test=" not($pos = $length)">
+		<a href="{$library_name}?a=d&amp;c={$collName}&amp;d={@selectedNode}.ns"><img src="interfaces/default/images/more.gif" border="0" align="absbottom" /></a>
+	      </xsl:if>
+	    </td>
+	  </tr>
+	</xsl:otherwise>
+      </xsl:choose>
+      <tr valign="middle">
+	<td align='center' valign='top' colspan='3'>
+	  <form name="GotoForm" method="get" action="{$library_name}">
+	    <input type='hidden' name='a' value='d'/>
+	    <input type='hidden' name='c' value='{$collName}'/>
+	    <input type='hidden' name='d' value='{@selectedNode}'/>
+	    <input type="text" name="gp" size="3" maxlength="4"/>
+	    <input type="submit"><xsl:attribute name='value'><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'document.gotopage')"/></xsl:attribute></input>
+	  </form>
+	</td>
+      </tr>
+    </table>
+  </xsl:template>
+  
+  <xsl:template name="enrichServices">
+    <xsl:param name="collName"/>
+    <xsl:variable name="docID" select="/page/pageRequest/paramList/param[@name='d']/@value"/>
+    <xsl:variable name="request-params" select="/page/pageRequest/paramList"/>
+    <xsl:for-each select="../serviceList/service">
+      <table border='1' cellspacing='0'>
+	<tr><td>
+	    <p /><xsl:value-of select="displayItem[@name='name']"/><p/>
+	    <form name="EnrichForm" method="get" action="{$library_name}">
+	      <xsl:apply-templates select="paramList"/>
+	      <input type='hidden' name='a' value='d'/>
+	      <input type='hidden' name='d' value='{$docID}'/>
+	      <input type='hidden' name='c' value='{$collName}'/>
+	      <xsl:if test='$request-params/param[@name="sib"]'>
+		<input type='hidden' name='sib'><xsl:attribute name='value'><xsl:value-of select='$request-params/param[@name="sib"]/@value'/></xsl:attribute></input></xsl:if>
+	      <input type='hidden' name='s' value='{@name}'/>
+	      <input type='hidden' name='p.a'><xsl:attribute name='value'><xsl:value-of select='$request-params/param[@name="p.a"]'/></xsl:attribute></input>
+	      <input type='hidden' name='p.sa'><xsl:attribute name='value'><xsl:value-of select='$request-params/param[@name="p.sa"]'/></xsl:attribute></input>
+	      <input type='hidden' name='p.s'><xsl:attribute name='value'><xsl:value-of select='$request-params/param[@name="p.s"]'/></xsl:attribute></input>
+	      <input type='hidden' name='end' value='1'/>
+	      <input type="submit"><xsl:attribute name="value"><xsl:value-of select="displayItem[@name='submit']"/></xsl:attribute></input>
+	    </form>
+	  </td></tr>
+      </table>
+    </xsl:for-each>
+  </xsl:template>
+
+  <xsl:template match="paramList" mode="hidden">
+    <xsl:for-each select="param">
+      <input type='hidden' name='{@name}' value='{@value}'/><xsl:text>
+      </xsl:text>
+    </xsl:for-each>
+  </xsl:template>
+  
+  <xsl:template name="documentArrows">
+    <xsl:param name="collName"/>
+    <div class="documentarrows">
+       <xsl:call-template name="documentArrow">
+        <xsl:with-param name="collName" select="$collName"/>
+       <xsl:with-param name="direction">back</xsl:with-param>
+     </xsl:call-template>
+    <xsl:call-template name="documentArrow">
+      <xsl:with-param name="collName" select="$collName"/>
+      <xsl:with-param name="direction">forward</xsl:with-param>
+    </xsl:call-template>
+    </div>
+    
+  </xsl:template>
+  
+  <xsl:template name="documentArrow">
+    <xsl:param name="collName"/>
+    <xsl:param name="direction"/>
+    <xsl:variable name="request-params" select="/page/pageRequest/paramList"/>
+    <xsl:if test='$request-params/param[@name="dt"]/@value != "simple"'>  
+    <a><xsl:attribute name="href"><xsl:value-of select="$library_name"/>?a=d&amp;c=<xsl:value-of select="$collName"/>&amp;d=<xsl:value-of select="@selectedNode"/><xsl:choose><xsl:when test="$direction='back'">.pp</xsl:when><xsl:otherwise>.np</xsl:otherwise></xsl:choose>&amp;sib=1&amp;p.s=<xsl:value-of select='$request-params/param[@name="p.s"]/@value'/>&amp;p.sa=<xsl:value-of select='$request-params/param[@name="p.sa"]/@value'/>&amp;p.a=<xsl:value-of select='$request-params/param[@name="p.a"]/@value'/></xsl:attribute><xsl:choose><xsl:when test="$direction='back'"><img class="lessarrow" src="interfaces/default/images/less.gif" /></xsl:when><xsl:otherwise><img class="morearrow" src="interfaces/default/images/more.gif"  /></xsl:otherwise></xsl:choose></a>
+    </xsl:if> 
+  </xsl:template>
+</xsl:stylesheet>
+
+
+
+
Index: /greenstone3/trunk/web/interfaces/default/transform/help.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/default/transform/help.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/transform/help.xsl	(revision 14125)
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+  
+   <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+
+  <xsl:output method="html"/>  
+  
+  <xsl:template name="pageTitle">
+    <xsl:choose><xsl:when test="/page/pageResponse/*/displayItem[@name='name']"><xsl:value-of select="/page/pageResponse/*/displayItem[@name='name']"/></xsl:when><xsl:otherwise><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'gsdl')"/></xsl:otherwise></xsl:choose>: <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'help_t')"/>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName" select="/page/pageRequest/paramList/param[@name='c']/@value"/>
+    <xsl:call-template name="standardPageBanner">
+      <xsl:with-param name="collName" select="$collName"/>
+      <xsl:with-param name="pageType">help</xsl:with-param>
+    </xsl:call-template>
+    <xsl:call-template name="navigationBar">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>      
+    
+    some help text goes here
+  </xsl:template>
+ 
+</xsl:stylesheet>
Index: /greenstone3/trunk/web/interfaces/default/transform/home.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/default/transform/home.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/transform/home.xsl	(revision 14125)
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+
+  <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+
+  <xsl:output method="html"/>  
+
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'gsdl')"/>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+  <xsl:template match="pageResponse">
+    <xsl:call-template name="greenstonePageBanner"/> 
+    <xsl:apply-templates select="serviceList/service[@name='TextQuery']"/>
+    <xsl:apply-templates select="collectionList"/>   
+    <xsl:apply-templates select="serviceClusterList"/>
+    <xsl:apply-templates select="serviceList"/>
+  </xsl:template>
+
+  <xsl:template match="collectionList">
+   <ul id="collectionlist">
+    <xsl:for-each select="collection"> 
+      <li>
+      
+           <xsl:choose>
+              <xsl:when test="displayItem[@name='icon']">
+              <a href="{$library_name}?a=p&amp;sa=about&amp;c={@name}">
+                <img>
+	           <xsl:attribute name="src">
+	             <xsl:value-of select="metadataList/metadata[@name='httpPath']"/>/images/<xsl:value-of select="displayItem[@name='icon']"/>
+	           </xsl:attribute>
+	           <xsl:attribute name="alt">
+	                <xsl:value-of select="displayItem[@name='name']"/>
+	           </xsl:attribute>
+	         </img> 
+               </a>  
+	      </xsl:when>
+              <xsl:otherwise>
+               <a class="noimage" href="{$library_name}?a=p&amp;sa=about&amp;c={@name}">  
+                 <xsl:value-of select="displayItem[@name='name']"/>
+               </a>
+              </xsl:otherwise>
+           </xsl:choose>         
+	 
+       </li>
+    </xsl:for-each> 
+   </ul>
+  </xsl:template> 
+  
+  <xsl:template match="serviceClusterList">
+    <xsl:for-each select="serviceCluster"> 
+      <a href="{$library_name}?a=p&amp;sa=about&amp;c={@name}"><xsl:value-of select='@name'/><xsl:value-of select="displayItem[@name='name']"/></a>
+    </xsl:for-each>
+  </xsl:template>
+
+  <xsl:template match="service[@name='TextQuery']">
+    <div class="QuickSearch">
+      <form name="QuickSearch" method="get" action="{$library_name}">
+	<input type="hidden" name="a" value="q"/>
+	<input type="hidden" name="rt" value="rd"/>
+	<input type="hidden" name="s" value="{@name}"/>
+	<input type="hidden" name="s1.collection" value="all"/>
+	<input type="text" name="s1.query" size="20"/>
+	<input type="submit" value="Quick Search"/>
+      </form>
+    </div>
+  </xsl:template>
+
+  <xsl:template match="serviceList">
+    <xsl:call-template name="dividerBar"/>
+    <ul id="servicelist">
+    <xsl:for-each select="service[@type='query']">
+      <li><a href="{$library_name}?a=q&amp;rt=d&amp;s={@name}"><xsl:value-of select="displayItem[@name='name']"/></a><xsl:value-of select="displayItem[@name='description']"/></li>
+      </xsl:for-each>
+    </ul>
+    </xsl:template>
+</xsl:stylesheet>  
+
+
Index: /greenstone3/trunk/web/interfaces/default/transform/html.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/default/transform/html.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/transform/html.xsl	(revision 14125)
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+  
+  <xsl:output method="html"/>  
+
+  <xsl:template match="page">
+    <html>
+      <head></head>
+      <frameset rows="68,*" noresize="" border="0">
+	<frame frameborder="0"><xsl:attribute name="src">?a=p&amp;sa=nav&amp;c=<xsl:value-of select="/page/pageRequest/paramList/param[@name='c']/@value" /></xsl:attribute></frame>
+	<frame frameborder="0"><xsl:attribute name="src"><xsl:value-of select="/page/pageRequest/paramList/param[@name='url']/@value"/></xsl:attribute></frame>
+	<noframes>
+	  <p><xsl:value-of select="util:getInterfaceText('default', /page/@lang, 'textframebrowser')"/></p>
+	</noframes>
+      </frameset>
+    </html>
+  </xsl:template>
+
+</xsl:stylesheet>
Index: /greenstone3/trunk/web/interfaces/default/transform/nav.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/default/transform/nav.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/transform/nav.xsl	(revision 14125)
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+  
+   <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+
+  <xsl:output method="html"/>  
+  
+  <xsl:template match="page">
+    <html>
+      <head>
+	<title>
+	  <xsl:call-template name="pageTitle"/><xsl:text> </xsl:text>
+	</title>
+	<xsl:call-template name="globalStyle"/>
+	<base target="_top"/>
+      </head>
+      <body style="background-image: none;">
+	<xsl:apply-templates select="pageResponse"/>
+      </body>
+    </html>
+  </xsl:template>
+
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="/page/pageResponse/*/displayItem[@name='name']"/>
+  </xsl:template>
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName" select="/page/pageRequest/paramList/param[@name='c']/@value"/>
+    <div align="right">
+    <xsl:call-template name="top-buttons">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+      </div>
+    <xsl:call-template name="navigationBar">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>      
+  </xsl:template>
+
+</xsl:stylesheet>
Index: /greenstone3/trunk/web/interfaces/default/transform/pref.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/default/transform/pref.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/transform/pref.xsl	(revision 14125)
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+  
+   <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+
+  <xsl:output method="html"/>  
+  
+  <xsl:template name="pageTitle">
+    <xsl:choose><xsl:when test="/page/pageResponse/*/displayItem[@name='name']"><xsl:value-of select="/page/pageResponse/*/displayItem[@name='name']"/></xsl:when><xsl:otherwise><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'gsdl')"/></xsl:otherwise></xsl:choose>: <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref_t')"/>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName" select="/page/pageRequest/paramList/param[@name='c']/@value"/>
+    
+   <xsl:variable name="tidyoption"><xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='tidyoption']"/></xsl:variable>
+      
+    <xsl:call-template name="standardPageBanner">
+      <xsl:with-param name="collName" select="$collName"/>
+      <xsl:with-param name="pageType">pref</xsl:with-param>
+    </xsl:call-template>
+
+    <xsl:call-template name="navigationBar">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>      
+    <div id="qureyform">
+    <form name="PrefForm" method="get" action="{$library_name}">
+      <input type='hidden' name='a' value='p'/>
+      <input type='hidden' name='sa' value='pref'/>
+      <input type='hidden' name='c' value="{$collName}"/>
+      <div class="formheading"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref.prespref')"/></div>
+      <ul id="presprefs"><xsl:call-template name="pres-prefs"/></ul>
+      <ul id="berrybasketprefs" ><xsl:call-template name="berrybasket-prefs"/></ul>
+      
+      <xsl:if test="$tidyoption='tidy'">
+      	<ul id="bookprefs"><xsl:call-template name="book-prefs"/></ul>
+      </xsl:if>
+      
+      <div class="formheading"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref.searchpref')"/></div>
+      <ul id="searchprefs"><xsl:call-template name="search-prefs"/></ul>
+      <input type='submit'><xsl:attribute name="value"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref.set_prefs')"/></xsl:attribute></input>
+       </form>
+   </div>
+  </xsl:template>
+  
+  <xsl:template name="pres-prefs">
+     <li><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref.interfacelang')"/> <xsl:call-template name="lang-list"/></li>
+      <li><span class="rightspace"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref.encoding')"/></span>x</li>
+    </xsl:template>
+ 
+  <xsl:template name="lang-list">
+    <xsl:variable name="current" select="/page/@lang"/>
+    <select name="l">
+      <xsl:for-each select="/page/pageResponse/languageList/language">
+	<option value="{@name}"><xsl:if test="@name=$current"><xsl:attribute name="selected"></xsl:attribute></xsl:if><xsl:value-of select="displayItem[@name='name']"/></option>
+      </xsl:for-each>
+    </select>
+  </xsl:template>
+  
+  <xsl:template name="search-prefs">
+    <xsl:variable name="hits"><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name='hitsPerPage']"><xsl:value-of select="/page/pageRequest/paramList/param[@name='hitsPerPage']/@value"/></xsl:when><xsl:otherwise>20</xsl:otherwise></xsl:choose></xsl:variable> 
+    <li><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref.hitsperpage')"/> 
+          <select name="hitsPerPage">
+	    <option value="20"><xsl:if test="$hits=20"><xsl:attribute name="selected"></xsl:attribute></xsl:if>20</option> 
+	    <option value="50"><xsl:if test="$hits=50"><xsl:attribute name="selected"></xsl:attribute></xsl:if>50</option>
+	    <option value="100"><xsl:if test="$hits=100"><xsl:attribute name="selected"></xsl:attribute></xsl:if>100</option>
+	    <option value="-1"><xsl:if test="$hits=-1"><xsl:attribute name="selected"></xsl:attribute></xsl:if><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref.all')"/></option>
+	  </select>
+    </li>
+  </xsl:template>
+
+ <xsl:template name="berrybasket-prefs">
+      <xsl:variable name="berrybasket"><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name='berrybasket']"><xsl:value-of select="/page/pageRequest/paramList/param[@name='berrybasket']/@value"/></xsl:when><xsl:otherwise>off</xsl:otherwise></xsl:choose></xsl:variable>
+     
+    <li><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref.berrybasket')"/> <select name="berrybasket">
+        <option value="on"><xsl:if test="$berrybasket='on'"><xsl:attribute name="selected"></xsl:attribute></xsl:if><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref.berrybasket.on')"/></option> 
+	<option value="off"><xsl:if test="$berrybasket='off'"><xsl:attribute name="selected"></xsl:attribute></xsl:if><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref.berrybasket.off')"/></option>
+      </select>
+    </li>
+  </xsl:template>
+
+<xsl:template name="book-prefs">
+      <xsl:variable name="book"><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name='book']"><xsl:value-of select="/page/pageRequest/paramList/param[@name='book']/@value"/></xsl:when><xsl:otherwise>off</xsl:otherwise></xsl:choose></xsl:variable>
+      
+    <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref.book')"/> <select name="book">
+        <option value="on"><xsl:if test="$book='on'"><xsl:attribute name="selected"></xsl:attribute></xsl:if><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref.berrybasket.on')"/></option> 
+	<option value="off"><xsl:if test="$book='off'"><xsl:attribute name="selected"></xsl:attribute></xsl:if><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref.berrybasket.off')"/></option>
+      </select>
+    
+  </xsl:template>
+</xsl:stylesheet>
Index: /greenstone3/trunk/web/interfaces/default/transform/process.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/default/transform/process.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/transform/process.xsl	(revision 14125)
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+
+  <xsl:include href="style.xsl"/>
+  <xsl:include href="service-params.xsl"/>
+
+  <xsl:output method="html"/>  
+
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="/page/pageResponse/serviceCluster/metadataList/metadata[@name='Title']"/>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="clusterName"><xsl:value-of select="/page/pageRequest/paramList/param[@name='c']/@value"/></xsl:variable>
+    <center>
+      <xsl:call-template name="standardPageBanner">
+	<xsl:with-param name="collName" select="$clusterName"/>
+      </xsl:call-template>
+      <xsl:call-template name="navigationBar">
+	<xsl:with-param name="collName" select="$clusterName"/>
+      </xsl:call-template>      
+      <xsl:apply-templates select="service">
+	<xsl:with-param name="clusterName" select="$clusterName"/>
+      </xsl:apply-templates>
+      <xsl:apply-templates select="status">
+	<xsl:with-param name="clusterName" select="$clusterName"/>
+      </xsl:apply-templates>
+    </center>
+  </xsl:template>
+
+  <xsl:template match="service">
+    <xsl:param name="clusterName"/>
+    <xsl:variable name='subaction' select="/page/pageRequest/@subaction"/>
+    <xsl:variable name='action' select="/page/pageRequest/@action"/>
+    <xsl:variable name='lang' select="/page/@lang"/>
+    <p/>
+    <form name="BuildForm" method="get" action="{$library_name}">
+      <xsl:apply-templates select="paramList"/>
+      <input type="hidden" name="a" value="{$action}"/>
+      <input type="hidden" name="c" value="{$clusterName}"/>
+      <input type="hidden" name="sa" value="p"/>
+      <input type="hidden" name='l' value='{$lang}'/>
+      <input type="hidden" name="s" value="{@name}"/>
+      <input type="hidden" name="rt" value="r"/>
+      <input type="submit"><xsl:attribute name="value"><xsl:value-of select="displayItem[@name='submit']"/></xsl:attribute></input>
+    </form>
+    <xsl:call-template name="dividerBar"/>
+  </xsl:template>
+  
+  <xsl:template match="status">
+    <xsl:param name="clusterName"/>
+    <center/>
+    <applet code="org.greenstone.gsdl3.build.StatusDisplay.class" codebase='lib' archive='gsdl3.jar, xercesImpl.jar, xml-apis.jar' width='600' height='150'>The status display applet.
+      <param name='library'><xsl:attribute name="value"><xsl:value-of select='$library_name'/>?a=pr&amp;rt=s&amp;c=<xsl:value-of select='$clusterName'/>&amp;s=<xsl:value-of select='/page/pageResponse/service/@name'/>&amp;o=xml&amp;ro=1&amp;l=<xsl:value-of select='/page/@lang'/>&amp;pid=<xsl:value-of select="@pid"/><xsl:apply-templates select="/page/pageResponse/service/paramList" mode="cgi"/></xsl:attribute></param>
+      <param name='initial_text'><xsl:attribute name="value"><xsl:value-of select="."/></xsl:attribute></param>
+      <param name='initial_code'><xsl:attribute name="value"><xsl:value-of  select="@code"/></xsl:attribute></param></applet>
+    <xsl:call-template name="dividerBar"/>
+  </xsl:template>
+
+  
+</xsl:stylesheet>  
+
Index: /greenstone3/trunk/web/interfaces/default/transform/query.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/default/transform/query.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/transform/query.xsl	(revision 14125)
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+  
+  <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+  <xsl:include href="service-params.xsl"/>
+  <xsl:include href="querytools.xsl"/>
+  <xsl:include href="berrytools.xsl"/>
+
+  <xsl:output method="html"/>
+
+   <xsl:variable name="berrybasketswitch"><xsl:value-of select="/page/pageRequest/paramList/param[@name='berrybasket']/@value"/></xsl:variable> 
+
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'gsdl')"/>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle">     	
+    <!--<xsl:if test="$berryBaskets = 'true'">-->
+    <xsl:if test="$berrybasketswitch = 'on'">
+      <xsl:call-template name="berryStyleSheet"/>
+      <xsl:call-template name="js-library"/>
+    </xsl:if>
+  </xsl:template>
+  
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName"><xsl:value-of select="/page/pageRequest/paramList/param[@name='c']/@value"/></xsl:variable> 
+    <xsl:call-template name="standardPageBanner">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+    <xsl:call-template name="navigationBar">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template> 
+    <div id="content">
+    <xsl:apply-templates select="service">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:apply-templates>
+   
+    <!--<xsl:if test="$berryBaskets = 'true'">-->
+    <xsl:if test="$berrybasketswitch = 'on'">
+      <xsl:call-template name="berrybasket"/>
+    </xsl:if>
+    <xsl:if test="documentNodeList">
+      <xsl:call-template name="query-response">
+	<xsl:with-param name="collName" select="$collName"/>
+      </xsl:call-template>
+    </xsl:if>
+    </div>
+   </xsl:template>
+
+
+  <!-- layout the response -->
+  <xsl:template name="query-response">
+    <xsl:param name="collName"/>
+    <xsl:call-template name="dividerBar"><xsl:with-param name='text'><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'query.results')"/></xsl:with-param></xsl:call-template>
+    
+    <!-- If query term information is available, display it -->
+    <xsl:call-template name="termInfo"/>
+    <xsl:call-template name="matchDocs"/>
+    
+     <!-- next and prev links at top of results-->
+   
+    <xsl:call-template name="resultNavigation">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+   
+    <!-- Display the matching documents -->  
+   
+    <xsl:call-template name="resultList">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+    
+    <!-- next and prev links at bottom of page -->
+    <xsl:call-template name="resultNavigation">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+
+  </xsl:template>
+  
+
+  <xsl:template match="service">
+    <xsl:param name="collName"/>
+    <xsl:variable name="subaction" select="../pageRequest/@subaction"/>
+    <div id="queryform">
+    <form name="QueryForm" method="get" action="{$library_name}">
+      <input type="hidden" name="a" value="q"/>
+      <input type="hidden" name="sa" value="{$subaction}"/>
+      <input type="hidden" name="rt" value="rd"/>
+      <input type="hidden" name="s" value="{@name}"/>
+      <input type="hidden" name="c" value="{$collName}"/>
+      <xsl:if test="not(paramList/param[@name='startPage'])">
+	<input type="hidden" name="startPage" value="1"/>
+      </xsl:if>
+      <xsl:apply-templates select="paramList"/>
+      <input type="submit"><xsl:attribute name="value"><xsl:value-of select="displayItem[@name='submit']"/></xsl:attribute></input>
+    </form>
+    </div>
+  </xsl:template>
+   
+</xsl:stylesheet>  
+
+
+
+
+
+
Index: /greenstone3/trunk/web/interfaces/default/transform/querytools.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/default/transform/querytools.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/transform/querytools.xsl	(revision 14125)
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+
+  <!-- have changed this so it uses service hitsPerPage and startPage if the service description has a param called hitsPerPage,  otherwise uses interface ones -->
+  <xsl:template name="resultNavigation">
+    <xsl:param name="collName"/>
+   <div class="resultnavigation">  
+  <!-- hits type -->
+    <xsl:variable name='ht'>
+      <xsl:choose>
+	<xsl:when test="/page/pageResponse/service/paramList/param[@name='hitsPerPage']">s</xsl:when>
+	<xsl:otherwise>i</xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    
+    <xsl:variable name="param-list" select="/page/pageRequest/paramList"/>
+    <!-- hits per page -->
+    <xsl:variable name="hpp">
+      <xsl:choose>
+	<xsl:when test="$ht='s'"><xsl:value-of select="$param-list/param[@name='s1.hitsPerPage']/@value"/></xsl:when>
+	<xsl:when test="$param-list/param[@name='hitsPerPage']"><xsl:value-of select="$param-list/param[@name='hitsPerPage']/@value"/></xsl:when>
+	<xsl:otherwise>20</xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <!-- total docs - this may be in numDocsMatched or numDocsReturned metadata -->
+    <xsl:variable name="td">
+      <xsl:choose>
+	<xsl:when test="/page/pageResponse/metadataList/metadata[@name='numDocsReturned']">
+	  <xsl:value-of select="/page/pageResponse/metadataList/metadata[@name='numDocsReturned']"/>
+	</xsl:when>
+	<xsl:when test="/page/pageResponse/metadataList/metadata[@name='numDocsMatched']">
+	  <xsl:value-of select="/page/pageResponse/metadataList/metadata[@name='numDocsMatched']"/>
+	</xsl:when>
+	<xsl:otherwise> <!-- this is just a fall back - shoudl always have the metadata -->
+	  <xsl:value-of select="count(/page/pageResponse/documentNodeList/documentNode)"/>
+	</xsl:otherwise>	
+      </xsl:choose>
+    </xsl:variable>
+
+    <!-- only continue if hpp != -1 and td > hpp -->
+    <xsl:if test="not($hpp=-1) and $td &gt; $hpp">
+      <!-- start page -->
+      <xsl:variable name="here">
+	<xsl:choose>
+	  <xsl:when test="$ht='s'"><xsl:value-of select="$param-list/param[@name='s1.startPage']/@value"/></xsl:when>
+	  <xsl:when test="$param-list/param[@name='startPage']"><xsl:value-of select="$param-list/param[@name='startPage']/@value"/></xsl:when>
+	  <xsl:otherwise>1</xsl:otherwise>
+	</xsl:choose>
+      </xsl:variable>
+      <xsl:variable name="sa" select="/page/pageRequest/@subaction"/>
+      <xsl:variable name="service" select="$param-list/param[@name='s']/@value"/>
+      <xsl:variable name="prev" select="$here - 1"/>
+      <xsl:variable name="next" select="$here + 1"/>
+      <xsl:variable name="page-param"><xsl:if test="$ht='s'">s1.</xsl:if>startPage</xsl:variable>
+     
+      <div>   
+	  <div>
+	     <xsl:if test="$here &gt; 1"><a href="{$library_name}?a=q&amp;sa={$sa}&amp;c={$collName}&amp;s={$service}&amp;rt=rd&amp;{$page-param}={$prev}"><img src="interfaces/default/images/less.gif" width='30' height='16' border='0' align='top'/><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'query.matches')"/><xsl:text> </xsl:text><xsl:value-of select="number(($prev - 1)*$hpp + 1)"/> - <xsl:value-of select="number(($prev * $hpp))"/></a></xsl:if>
+	   
+	   
+	      <xsl:if test="(($here * $hpp) + 1)  &lt; $td">
+		<xsl:variable name='m' select="number($next * $hpp)"/>
+		<xsl:variable name='mm'><xsl:choose><xsl:when test="$m &lt; $td"><xsl:value-of select='$m'/></xsl:when><xsl:otherwise><xsl:value-of select='$td'/></xsl:otherwise></xsl:choose></xsl:variable>
+		<a href="{$library_name}?a=q&amp;sa={$sa}&amp;c={$collName}&amp;s={$service}&amp;rt=rd&amp;{$page-param}={$next}"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'query.matches')"/><xsl:text> </xsl:text><xsl:value-of select="number(($next - 1)*$hpp + 1)"/> - <xsl:value-of select="$mm"/><img src="interfaces/default/images/more.gif" width='30' height='16' border='0' align='top'/></a></xsl:if></div>
+	</div>
+     </xsl:if>
+   </div>
+  </xsl:template>
+    
+  <xsl:template name="matchDocs">
+    <!-- If the number of matching documents is known, display it -->
+    <div id="matchdocs">
+    <xsl:variable name="numDocsMatched" select="metadataList/metadata[@name='numDocsMatched']"/>
+    <xsl:variable name="numDocsReturned" select="metadataList/metadata[@name='numDocsReturned']"/>
+    <xsl:choose>
+      <xsl:when test="$numDocsMatched='0' or $numDocsReturned='0'">
+	<xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'query.nodocsmatch')"/>
+      </xsl:when>
+      <xsl:when test="$numDocsMatched='1' or $numDocsReturned='1'">
+	<xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'query.onedocsmatch')"/>
+      </xsl:when>
+      <xsl:when test="$numDocsMatched">
+	<xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'query.manydocsmatch', $numDocsMatched)"/>
+	<xsl:if test="$numDocsReturned"> (<xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'query.docsreturned', $numDocsReturned)"/>)</xsl:if>
+      </xsl:when>
+      <xsl:when test="$numDocsReturned">
+	<xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'query.atleastdocsmatch', $numDocsReturned)"/>
+      </xsl:when>
+    </xsl:choose>
+   </div>
+  </xsl:template>
+
+  <!-- paging is now done by the query action, so here we just print out all the docs that we have -->
+  <xsl:template name="resultList">
+     <xsl:param name="collName"/>
+    <ul id="resultlist"> 
+     <xsl:for-each select="documentNodeList/documentNode">
+	<li><table>
+	  <xsl:call-template name="documentNodeWrapper">
+	    <xsl:with-param name="collName" select="$collName"/>
+	    <xsl:with-param name="serviceName" select="/page/pageResponse/service/@name"/>
+	  </xsl:call-template>
+            </table>
+	</li>	    
+      </xsl:for-each>  
+    </ul>
+  </xsl:template>
+  
+  <!-- this is a wrapper node, which the interface can use to add stuff into the query results that isn't part of and doesn't depend on the documentNode template which may come from the collection -->
+  <xsl:template name="documentNodeWrapper">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+    <xsl:variable name="berrybasketswitch"><xsl:value-of select="/page/pageRequest/paramList/param[@name='berrybasket']/@value"/></xsl:variable>
+    <!--<xsl:if test="$berryBaskets = 'true'">-->
+      <xsl:if test="$berrybasketswitch = 'on'">
+      <xsl:call-template name="addBerry">
+	<xsl:with-param name="collName" select="$collName"/>
+      </xsl:call-template>
+    </xsl:if>
+    <xsl:apply-templates select=".">
+      <xsl:with-param name="collName" select="$collName"/>
+      <xsl:with-param name="serviceName" select="$serviceName"/>
+    </xsl:apply-templates>
+  </xsl:template>
+
+  
+  <!-- the default doc node template for the query results -->
+  <!-- eventually shouldn't need sib arg here -->
+  <xsl:template match="documentNode">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+     <a><xsl:attribute name="href"><xsl:value-of select='$library_name'/>?a=d&amp;c=<xsl:value-of select='$collName'/>&amp;d=<xsl:value-of select='@nodeID'/><xsl:if test="@nodeType='leaf'">&amp;sib=1</xsl:if>&amp;dt=<xsl:value-of select='@docType'/>&amp;p.a=q&amp;&amp;p.sa=<xsl:value-of select="/page/pageRequest/@subaction"/>&amp;p.s=<xsl:value-of select="$serviceName"/></xsl:attribute>
+	<xsl:apply-templates select="." mode="displayNodeIcon"/>
+      </a>
+    <span><xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name='Title']"/></span>
+  </xsl:template>
+
+  <xsl:template name="termInfo">
+   <div class="terminfo">
+    <xsl:if test="count(termList/term) > 0">
+     <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'query.wordcount')"/>
+	<xsl:for-each select="termList/term">
+	  <xsl:if test="position() > 1">, </xsl:if>
+	  <xsl:value-of select="@name"/>: <xsl:value-of select="@freq"/> 
+	</xsl:for-each>
+    </xsl:if>
+  </div>
+  </xsl:template>
+
+</xsl:stylesheet>
+
+
Index: /greenstone3/trunk/web/interfaces/default/transform/service-params.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/default/transform/service-params.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/transform/service-params.xsl	(revision 14125)
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  extension-element-prefixes="java">
+
+<!-- handling of the different types of params on a service form 
+  - these now only output the selection box/text box etc, not the name -->
+
+  <!-- the default param list handling -->
+  <xsl:template match="paramList">
+    <xsl:param name="ns">s1.</xsl:param>
+    <ul id="queryitemlist">
+      <xsl:for-each select="param">
+	<xsl:choose>
+	  <xsl:when test="@type='multi'">
+	    <li><xsl:apply-templates select='.'><xsl:with-param name="ns" select="$ns"/></xsl:apply-templates></li>
+	  </xsl:when>
+	  <xsl:otherwise>
+	    <xsl:variable name="pvalue"><xsl:apply-templates select="." mode="calculate-default"><xsl:with-param name="ns" select="$ns"/></xsl:apply-templates></xsl:variable>
+	      <li><xsl:value-of select="displayItem[@name='name']"/><xsl:apply-templates select="."><xsl:with-param name="default" select="$pvalue"/><xsl:with-param name="ns" select="$ns"/></xsl:apply-templates></li>
+	  </xsl:otherwise>
+	</xsl:choose>
+      </xsl:for-each>
+    </ul>
+  </xsl:template>
+ 
+  <!-- puts all the params into a=p&p=h type form - need to change this if use 
+  multi params  -->
+  <xsl:template match="paramList" mode="cgi">
+    <xsl:param name="ns">s1.</xsl:param>
+    <xsl:for-each select="param">
+      <xsl:variable name='pname' select="@name"/>
+      <xsl:text>&amp;</xsl:text><xsl:value-of select="$ns"/><xsl:value-of select="@name"/>=<xsl:apply-templates select="." mode="calculate-default"><xsl:with-param name='ns' select='$ns'/></xsl:apply-templates>
+    </xsl:for-each>
+  </xsl:template>
+
+  <xsl:template match="param" mode="calculate-default">
+    <xsl:param name="ns">s1.</xsl:param>
+    <xsl:variable name="pname"><xsl:value-of select="$ns"/><xsl:value-of select="@name"/></xsl:variable>
+    <xsl:choose>
+      <xsl:when test="/page/pageRequest/paramList/param[@name=$pname]">
+	<xsl:choose>
+	  <xsl:when test="@type='enum_multi'"><xsl:text>,</xsl:text>
+	    <xsl:for-each select="/page/pageRequest/paramList/param[@name=$pname]">
+	      <xsl:value-of select="@value"/>,
+	    </xsl:for-each>
+	  </xsl:when>
+	  <xsl:otherwise>
+	    <xsl:value-of select="/page/pageRequest/paramList/param[@name=$pname]/@value"/>
+	  </xsl:otherwise>
+	</xsl:choose>
+      </xsl:when>
+      <xsl:otherwise>
+	<xsl:value-of select="@default"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- invisible params - used by other stuff. in the query form, we set to teh default -->
+  <xsl:template match="param[@type='invisible']">
+    <xsl:param name="ns">s1.</xsl:param>
+    <input type='hidden' name='{$ns}{@name}' value='{@default}'/>
+  </xsl:template>
+  <!-- boolean params -->
+  <xsl:template match="param[@type='boolean']">
+    <xsl:param name="ns">s1.</xsl:param>
+    <xsl:param name="default"/>
+    <select name='{$ns}{@name}'>
+      <option value="0"><xsl:if test="$default='0'"><xsl:attribute name="selected"></xsl:attribute></xsl:if><xsl:value-of select="option[@name='0']/displayItem[@name='name']"/></option>
+      <option value="1"><xsl:if test="$default='1'"><xsl:attribute name="selected"></xsl:attribute></xsl:if><xsl:value-of select="option[@name='1']/displayItem[@name='name']"/></option>
+    </select>
+  </xsl:template>
+  
+  <!-- integer params -->
+  <xsl:template match="param[@type='integer']">
+    <xsl:param name="ns">s1.</xsl:param>
+    <xsl:param name="default"/>
+    <input type="text" name="{$ns}{@name}" size="3" value="{$default}"/>
+  </xsl:template>
+
+  <!-- single selection enum params -->
+  <xsl:template match="param[@type='enum_single']">
+    <xsl:param name="ns">s1.</xsl:param>
+    <xsl:param name="default"/>
+    <xsl:choose>
+      <xsl:when test="count(option) = 1">
+	<xsl:value-of select="option/displayItem[@name='name']"/>
+	<input type='hidden' name='{$ns}{@name}'><xsl:attribute name='value'><xsl:value-of  select='option/@name'/></xsl:attribute></input>
+      </xsl:when>
+      <xsl:otherwise>
+	<select name="{$ns}{@name}">
+	  <xsl:for-each select="option">
+	    <option value="{@name}"><xsl:if test="@name=$default"><xsl:attribute name="selected"></xsl:attribute></xsl:if><xsl:value-of select="displayItem[@name='name']"/></option>
+	  </xsl:for-each>
+	</select>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+
+  <!-- multiple selection enum params -->
+  <!-- how to do defaults for this?? -->
+  <xsl:template match="param[@type='enum_multi']">
+    <xsl:param name="ns">s1.</xsl:param>
+    <xsl:param name="default"/>
+    <select name="{$ns}{@name}" size='2'><xsl:attribute name="multiple"></xsl:attribute>
+      <xsl:for-each select="option">
+	<option value="{@name}"><xsl:if test="contains($default, concat(',', @name, ','))"><xsl:attribute name="selected"></xsl:attribute></xsl:if><xsl:value-of select="displayItem[@name='name']"/></option>
+      </xsl:for-each>
+    </select>
+  </xsl:template>
+ 
+  <!-- string params -->
+  <xsl:template match="param[@type='string']">
+    <xsl:param name="ns">s1.</xsl:param>
+    <xsl:param name="default"/>
+    <input type="text" name="{$ns}{@name}" size="50" value="{$default}"/>
+  </xsl:template>
+  
+  <!-- large string  params -->
+  <xsl:template match="param[@type='text']">
+    <xsl:param name="ns">s1.</xsl:param>
+    <xsl:param name="default"/>
+    <textarea name="{$ns}{@name}" cols="50" rows="3"><xsl:value-of select='$default'/></textarea>
+  </xsl:template>
+
+  <!-- multi params - params that are combinations of other params -->
+  <xsl:template match="param[@type='multi']">
+    <xsl:param name="ns">s1.</xsl:param>
+    <xsl:variable name="parent" select="@name"/>
+    <table>
+        <tr class="queryfieldheading"><xsl:value-of select="displayItem[@name='name']"/>
+      	<xsl:for-each select="param">
+	    <td class="queryfieldname"><xsl:value-of select="displayItem[@name='name']"/></td>
+	</xsl:for-each>
+        </tr>
+      
+        <xsl:apply-templates select="." mode="contents"><xsl:with-param name="occurs" select="@occurs"/><xsl:with-param name="ns" select="$ns"/></xsl:apply-templates>
+    </table>
+  </xsl:template>
+
+  <xsl:template match="param[@type='multi']" mode="contents">
+    <xsl:param name="ns">s1.</xsl:param>
+    <xsl:param name="occurs">1</xsl:param>
+    <xsl:variable name="pos" select="@occurs - $occurs"/>	
+    <tr class="queryfieldrow"><xsl:for-each select="param">
+	<xsl:variable name="pname" select="@name"/>
+	<xsl:variable name="values" select="/page/pageRequest/paramList/param[@name=$pname]/@value"/>
+	<td class="queryfieldcell"><xsl:choose>
+	    <xsl:when test="not(@ignore) or  @ignore != $pos">      
+	      <xsl:apply-templates select='.'><xsl:with-param name="default" select="java:org.greenstone.gsdl3.util.XSLTUtil.getNumberedItem($values, $pos)"/><xsl:with-param name="ns" select="$ns"/></xsl:apply-templates>
+	    </xsl:when>
+	    <xsl:otherwise><!-- put in a hidden placeholder -->
+	      <input type="hidden" name='{$ns}{@name}' value=''/>
+	    </xsl:otherwise>
+	  </xsl:choose></td>
+      </xsl:for-each></tr>
+    <!-- recursively call this template to get multiple entries -->
+    <xsl:if test="$occurs &gt; 1">
+      <xsl:apply-templates select="." mode="contents"><xsl:with-param name="occurs" select="$occurs - 1"/><xsl:with-param name="ns" select="$ns"/></xsl:apply-templates>
+    </xsl:if>
+  </xsl:template>
+
+  
+</xsl:stylesheet>  
+
+  <!-- a param list that puts params in pairs- wont work as is with new
+  param handling stuff -->
+  <!--
+  <xsl:template match="paramList">
+  <p/><table width="537">
+  <xsl:choose>
+  <xsl:when test='count(param)>4'>
+  <xsl:for-each select="param[position() mod 2 = 1]"> 
+  <tr><xsl:apply-templates select="."/>
+  <xsl:if test="following-sibling::param[1]"><xsl:apply-templates select='following-sibling::param[1]'/></xsl:if></tr>
+</xsl:for-each>
+</xsl:when>
+  <xsl:otherwise>
+  <xsl:for-each select="param">
+  <tr><xsl:apply-templates select='.'/></tr>
+</xsl:for-each>
+</xsl:otherwise>
+</xsl:choose>
+</table>
+</xsl:template>
+  -->
Index: /greenstone3/trunk/web/interfaces/default/transform/style.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/default/transform/style.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/transform/style.xsl	(revision 14125)
@@ -0,0 +1,323 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+
+  <!-- some global parameters - these are set by whoever is invoking the transformation -->
+  <xsl:param name="interface_name"/>
+  <xsl:param name="library_name"/>
+   <!-- global style info goes here  -->
+  <xsl:template name="globalStyle">
+    <link rel="stylesheet" href="interfaces/default/style/core.css" type="text/css"/>
+  </xsl:template>
+  
+  <!-- the main page layout template is here -->
+  <xsl:template match="page">
+    <xsl:variable name="bookswitch"><xsl:value-of select="/page/pageRequest/paramList/param[@name='book']/@value"/></xsl:variable>
+    <xsl:variable name="a"><xsl:value-of select="/page/pageRequest/paramList/param[@name='a']/@value"/></xsl:variable>
+
+    <xsl:choose> 
+      <xsl:when test="$bookswitch = 'flashxml' and $a = 'd'">
+         <html>
+   		  <xsl:call-template name="response" />
+        </html>
+      </xsl:when>
+
+      <xsl:otherwise>    
+        <html>
+     	 <xsl:call-template name="pageHead"/>
+          <body>
+           <div id="globalwrapper">
+   		  <xsl:call-template name="response" />
+		  <xsl:call-template name="greenstoneFooter"/>
+	   </div>
+          </body>
+        </html>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+ <xsl:template name="response">
+	  <xsl:apply-templates select="pageResponse"/>
+		  <xsl:if test="descendant::error">
+		    <script language="Javascript">
+		      <xsl:text disable-output-escaping="yes">
+			function removeAllChildren(node) {
+			 while (node.hasChildNodes()) {
+			  node.removeChild(node.firstChild);
+			 }
+			}
+
+		      function toggleHideError(obj) {
+		      if (obj.style.display == "none") {
+			obj.style.display = "";
+			hide_link = document.getElementById("hide");
+			removeAllChildren(hide_link);
+			hide_link.appendChild(document.createTextNode("Hide Error"));
+		      } else {
+			obj.style.display = "none";
+			hide_link = document.getElementById("hide");
+			removeAllChildren(hide_link);
+			hide_link.appendChild(document.createTextNode("Show Error"));
+			
+			}
+		      }
+		      </xsl:text>
+		    </script>
+		    <p align='right'><a id="hide" href="javascript:toggleHideError(error);">Show Error</a></p>
+		    <div id="error" style="display: none;">
+		      <xsl:apply-templates select="descendant::error"/>
+		    </div>
+		  </xsl:if>
+ </xsl:template>
+
+  <!-- put a space in the title in case the actual value is missing - mozilla will not display a page with no title-->
+  <xsl:template name="pageHead">
+    <head>
+      <title>
+	<xsl:call-template name="pageTitle"/><xsl:text> </xsl:text>
+      </title>
+      <xsl:call-template name="globalStyle"/>
+      <xsl:call-template name="pageStyle"/>
+    </head>
+  </xsl:template>
+
+
+  <xsl:template name="greenstonePageBanner">
+    <div id="banner">
+        <p>
+            <img src="interfaces/default/images/gsdlhead.gif"><xsl:attribute name="alt"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'gsdl')"/></xsl:attribute>
+            </img>
+	</p>
+    </div>
+    <div id="content">
+	<xsl:call-template name="dividerBar">
+            <xsl:with-param name="text" select="'select a collection'"/> 
+        </xsl:call-template>	
+      </div>
+  </xsl:template>
+
+  <xsl:template name="greenstoneFooter">
+      <div id="footer">
+         <xsl:call-template name="dividerBar">
+            <xsl:with-param name="text" select="util:getInterfaceText($interface_name, /page/@lang, 'gs3power')"/> 
+        </xsl:call-template>
+      </div>
+  </xsl:template>
+  
+  <xsl:template match="error">
+    Error: <xsl:value-of select="."/>
+  </xsl:template>
+
+  <xsl:template name="standardPageBanner">
+    <xsl:param name="collName"/>
+    <xsl:param name="pageType"/>
+    <xsl:variable name="this-element" select="/page/pageResponse/collection|/page/pageResponse/serviceCluster"/>
+    <div  id="banner">    
+     <p>
+	  <a href="{$library_name}?a=p&amp;sa=about&amp;c={$collName}">
+	    <xsl:choose>
+	      <xsl:when test="$this-element/displayItem[@name='icon']">
+		<img border="0">
+		  <xsl:attribute name="src">
+		    <xsl:value-of select="$this-element/metadataList/metadata[@name='httpPath']"/>/images/<xsl:value-of select="$this-element/displayItem[@name='icon']"/>
+		  </xsl:attribute>	
+		  <xsl:attribute name="alt">
+		    <xsl:value-of select="$this-element/displayItem[@name='name']"/>
+		  </xsl:attribute>
+		  <xsl:attribute name="title">
+		    <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'aboutpage')"/>
+		  </xsl:attribute>
+		</img>
+	      </xsl:when>
+	      <xsl:otherwise>
+		<xsl:value-of select="$this-element/displayItem[@name='name']"/>
+	      </xsl:otherwise>
+	    </xsl:choose>
+	  </a>
+	</p>
+        <ul id="bannerlist"> 
+	  <xsl:call-template name="top-buttons">
+	    <xsl:with-param name="collName" select="$collName"/>
+	    <xsl:with-param name="pageType" select="$pageType"/>
+	  </xsl:call-template>
+       </ul>
+    </div>
+   </xsl:template>
+  
+  <xsl:template name="top-buttons">
+    <xsl:param name="collName"/>
+    <xsl:param name="pageType"/>
+    	 <li><a  href="{$library_name}?a=p&amp;sa=home"><xsl:attribute name="title"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'home_tip')"/></xsl:attribute>
+	    <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'home_b')"/>
+	  </a></li>
+	<xsl:choose>
+	  <xsl:when test="$pageType='help'">
+	      <li><a><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'help_b')"/></a></li>
+	  </xsl:when>
+	  <xsl:otherwise>
+	    <li><a href="{$library_name}?a=p&amp;sa=help&amp;c={$collName}"><xsl:attribute name="title"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'help_tip')"/></xsl:attribute>
+		<xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'help_b')"/>
+	      </a></li>
+	    </xsl:otherwise>
+	</xsl:choose>
+	<xsl:choose>
+	  <xsl:when test="$pageType='pref'">
+	     <li><a><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref_b')"/></a></li>
+	   </xsl:when>
+	  <xsl:otherwise>
+	    <li><a href="{$library_name}?a=p&amp;sa=pref&amp;c={$collName}"><xsl:attribute name="title"><xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref_tip')"/></xsl:attribute>
+		<xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'pref_b')"/>
+	      </a></li>
+	    </xsl:otherwise>
+	</xsl:choose>
+  </xsl:template>
+
+  <xsl:template name="navigationBar">
+    <xsl:param name="collName"/>
+    <xsl:variable name="this-element" select="/page/pageResponse/collection|/page/pageResponse/serviceCluster"/>
+    <xsl:variable name="this-service" select="/page/pageResponse/service/@name"/>
+    <xsl:choose>
+    <xsl:when test="$this-element/serviceList/service">
+    <div id="navbar">
+        <ul id="navbarlist">
+	    <xsl:for-each select="$this-element/serviceList/service">
+	      <xsl:variable name="action"><xsl:choose>
+		  <xsl:when test="@name=$this-service">CURRENT</xsl:when>
+		  <xsl:when test="@type='query'">q</xsl:when>
+		  <xsl:when test="@type='browse'">b</xsl:when>
+		  <xsl:when test="@type='process'">pr</xsl:when>
+		  <xsl:when test="@type='applet'">a</xsl:when>
+		  <xsl:otherwise>DO_NOT_DISPLAY</xsl:otherwise>
+		</xsl:choose></xsl:variable>
+	      <xsl:choose>
+		<xsl:when test="$action='CURRENT'">
+		  <li><a ><xsl:value-of select="displayItem[@name='name']"/></a></li>
+		</xsl:when>
+		<xsl:when test="$action !='DO_NOT_DISPLAY'">
+		  <li><a href="{$library_name}?a={$action}&amp;rt=d&amp;s={@name}&amp;c={$collName}"><xsl:if test="displayItem[@name='description']"><xsl:attribute name='title'><xsl:value-of select="displayItem[@name='description']"/></xsl:attribute></xsl:if><xsl:value-of select="displayItem[@name='name']"/></a></li>
+		</xsl:when>
+	      </xsl:choose>
+	    </xsl:for-each>
+           </ul>
+	 </div> 
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:call-template name="dividerBar">
+            <xsl:with-param name="text" select="'&#160;'"/> 
+        </xsl:call-template>            
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+  
+  
+  <xsl:template name="dividerBar">
+   <xsl:param name='text'/>
+      <xsl:choose>
+      <xsl:when test="$text">
+	 <div class="divbar"><xsl:value-of select="$text"/></div>
+      </xsl:when>
+      <xsl:otherwise>
+	 <div class="divbar"><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text></div>
+      </xsl:otherwise>
+    </xsl:choose> 
+  </xsl:template>
+
+  <!-- Display the appropriate image, depending on the node type -->
+  <xsl:template match="documentNode" mode="displayNodeIcon">
+      
+    <!-- Root node: book icon (open or closed) -->
+    <xsl:choose>
+      <xsl:when test="@nodeType='root'">
+	<xsl:choose>
+	  <xsl:when test="documentNode">
+	    <xsl:call-template name="openbookimg">
+	      <xsl:with-param name="title">Close this book</xsl:with-param>
+	    </xsl:call-template>
+	  </xsl:when>
+	  <xsl:otherwise>
+	    <xsl:call-template name="closedbookimg">
+	      <xsl:with-param name="title">Open this document and view contents</xsl:with-param>
+	    </xsl:call-template>
+	  </xsl:otherwise>
+	</xsl:choose>
+      </xsl:when>
+      
+      <!-- Internal node: folder icon (open or closed) -->
+      <xsl:when test="@nodeType='internal'">
+	<xsl:choose>
+	  <xsl:when test="documentNode">
+	    <xsl:call-template name="openfolderimg">
+	      <xsl:with-param name="title">Close this folder</xsl:with-param>
+	    </xsl:call-template>
+	  </xsl:when>
+	  <xsl:otherwise>
+	    <xsl:call-template name="closedfolderimg">
+	      <xsl:with-param name="title">Open this folder and view contents</xsl:with-param>
+	    </xsl:call-template>
+	  </xsl:otherwise>
+	</xsl:choose>
+      </xsl:when>
+      
+      <!-- Leaf node: page icon, and this is the default -->
+      <xsl:otherwise>
+	<xsl:call-template name="textpageimg">
+	  <xsl:with-param name="title">View the document</xsl:with-param>
+	</xsl:call-template>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template name="openbookimg">
+    <xsl:param name="alt"/>
+    <xsl:param name="title"/>
+    <img  border="0" width="28" height="23"
+      src="interfaces/default/images/openbook.gif"
+      alt="{$alt}" title="{$title}"/>
+  </xsl:template>
+
+  <xsl:template name="closedbookimg">
+    <xsl:param name="alt"/>
+    <xsl:param name="title"/>
+    <img border="0" width="18" height="11"
+      src="interfaces/default/images/book.gif"
+      alt="{$alt}" title="{$title}"/>
+  </xsl:template>
+
+  <xsl:template name="openfolderimg">
+    <xsl:param name="alt"/>
+    <xsl:param name="title"/>
+    <img border="0" width="23" height="15"
+      src="interfaces/default/images/openfldr.gif"
+      alt="{$alt}" title="{$title}"/>
+  </xsl:template>
+
+  <xsl:template name="closedfolderimg">
+    <xsl:param name="alt"/>
+    <xsl:param name="title"/>
+    <img  border="0" width="23" height="15"
+      src="interfaces/default/images/clsdfldr.gif"
+      alt="{$alt}" title="{$title}"/>
+  </xsl:template>
+
+  <xsl:template name="textpageimg">
+    <xsl:param name="alt"/>
+    <xsl:param name="title"/>
+    <img  border="0" width="16" height="21"
+      src="interfaces/default/images/itext.gif"
+      alt="{$alt}" title="{$title}"/>
+  </xsl:template>
+
+  <xsl:template name="bookshelfimg">
+    <xsl:param name="alt"/>
+    <xsl:param name="title"/>
+    <img  border="0" width="20" height="16"
+      src="interfaces/default/images/bshelf.gif"  
+      alt="{$alt}" title="{$title}"/>
+  </xsl:template>
+</xsl:stylesheet>  
+
+
Index: /greenstone3/trunk/web/interfaces/default/transform/system.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/default/transform/system.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/default/transform/system.xsl	(revision 14125)
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  extension-element-prefixes="java">
+  
+  <xsl:include href="style.xsl"/>
+  
+    <xsl:template name="pageTitle">
+    <xsl:value-of select="java:org.greenstone.gsdl3.util.XSLTUtil.getInterfaceText($interface_name, /page/@lang, 'gsdl')"/>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+  <xsl:template match="pageResponse">
+    <xsl:value-of select="status"/>
+  </xsl:template>
+  
+</xsl:stylesheet>
Index: /greenstone3/trunk/web/interfaces/nzdl/interfaceConfig.xml
===================================================================
--- /greenstone3/trunk/web/interfaces/nzdl/interfaceConfig.xml	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/nzdl/interfaceConfig.xml	(revision 14125)
@@ -0,0 +1,27 @@
+<interfaceConfig baseInterface="classic">
+  <actionList>
+    <action name='p' class='PageAction'>
+      <subaction name='home' xslt='home.xsl'/>
+      <subaction name='about' xslt='about.xsl'/>
+      <subaction name='gsdl' xslt='gsdl.xsl'/>
+      <subaction name='help' xslt='help.xsl'/>
+      <subaction name='pref' xslt='pref.xsl'/>
+      <subaction name='nav' xslt='nav.xsl'/>
+      <subaction name="html" xslt="html.xsl"/>
+      <subaction name='abexpl' xslt='abexpl.xsl'/>
+    </action>
+    <action name='q' class='QueryAction' xslt='query.xsl'/>
+    <action name='b' class='GS2BrowseAction' xslt='classifier.xsl'/>
+    <action name='a' class='AppletAction' xslt='applet.xsl'/>
+    <action name='d' class='DocumentAction' xslt='document.xsl'/>
+    <action name='pr' class='ProcessAction' xslt='process.xsl'/>
+    <action name='s' class='SystemAction' xslt='system.xsl'/>
+  </actionList>
+  <languageList>
+    <language name='en' displayname='English' default_encoding='utf-8'/>
+    <language name='fr' displayname='French' default-encoding='utf-8'/>
+  </languageList>
+  <optionList>
+    <option name="highlightQueryTerms" value="true"/>
+  </optionList>
+</interfaceConfig>
Index: /greenstone3/trunk/web/interfaces/nzdl/transform/gsdl-text.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/nzdl/transform/gsdl-text.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/nzdl/transform/gsdl-text.xsl	(revision 14125)
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  extension-element-prefixes="java">
+
+  <xsl:template name="aboutgs">about the greenstone software</xsl:template>
+  <xsl:template name="textgreenstone1">
+Greenstone is a suite of software which has the ability to serve digital
+library collections and build new collections.  It provides a new way of
+organizing information and publishing it on the Internet or on CD-ROM.
+Greenstone is produced by the New Zealand Digital Library Project at the
+University of Waikato, and distributed in cooperation with UNESCO and the
+Human Info NGO. It is open-source software, available from
+<i>http://greenstone.org</i> under the terms of the GNU General Public
+License.
+  </xsl:template>
+
+  <xsl:template name="textgreenstone2">
+The New Zealand Digital Library website (<a href="http://nzdl.org">http://nzdl.org</a>) contains numerous example
+collections, all created with the Greenstone software, which are publicly
+available for you to peruse. They exemplify various searching and browsing
+options, and include collections in Arabic, Chinese, French, Maori, and
+Spanish, as well as English. There are also some music collections.
+  </xsl:template>
+
+  <xsl:template name="textplatformtitle">platform</xsl:template>
+  <xsl:template name="textgreenstone3">
+Greenstone runs on Windows and Unix. The distribution includes ready-to-use
+binaries for all versions of Windows, and for Linux. It also includes
+complete source code for the system, which can be compiled using Microsoft
+C++ or gcc.  Greenstone works with associated software that is also freely
+available: the Apache Webserver and PERL. The user interface uses a Web
+    browser: typically Netscape Navigator or Internet Explorer.
+  </xsl:template>
+
+  <xsl:template name="textgreenstone4">
+Many document collections are distributed on CD-ROM using the Greenstone
+software. For example, the <i>Humanity Development Library</i> contains
+1,230 publications ranging from accounting to water sanitation. It runs on
+minimal computing facilities such as those typically found in developing
+countries. The information can be accessed by searching, browsing by
+subject, browsing by titles, browsing by organisation, browsing a list of
+how-tos, and by randomly viewing the book covers.
+  </xsl:template>
+
+  <xsl:template name="textcustomisationtitle">customisation</xsl:template>
+  <xsl:template name="textgreenstone5">
+Greenstone is specifically designed to be highly extensible and
+customisable. New document and metadata formats are accommodated by writing
+"plugins" (in Perl). Analogously, new metadata browsing structures can be
+implemented by writing "classifiers." The user interface look-and-feel can
+be altered using "macros" written in a simple macro language. A Corba
+protocol allows agents (e.g. in Java) to use all the facilities associated
+with document collections. Finally, the source code, in C++ and Perl, is
+available and accessible for modification.
+  </xsl:template>
+
+<xsl:template name="textdocumentationtitle">documentation</xsl:template>
+<xsl:template name="textdocuments">Extensive documentation for the Greenstone software is available.</xsl:template>
+
+  <xsl:template name="textmailinglisttitle">mailing list</xsl:template>
+  <xsl:template name="textmailinglist">
+There is a mailing list intended primarily for discussions about the
+Greenstone digital library software.  Active users of Greenstone should
+consider joining the mailing list and contributing to the discussions.
+To subscribe, go to  <a href="https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users">https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users</a>.
+
+To send a message to the list, address it to <a
+href="mailto:greenstone-users@list.scms.waikato.ac.nz"
+>greenstone-users@list.scms.waikato.ac.nz</a>.
+</xsl:template>
+
+  <xsl:template name="textbugstitle">bugs</xsl:template>
+  <xsl:template name="textreport">
+We want to ensure that this software works well for you.  Please report any
+bugs to <a href="mailto:greenstone@cs.waikato.ac.nz">greenstone@cs.waikato.ac.nz</a>
+  </xsl:template>
+
+<xsl:template name="textgs3title">in the works</xsl:template>
+
+<xsl:template name="textgs3">Greenstone 3 is a complete redesign and 
+reimplementation which 
+retains all the advantages of Greenstone 2 (the current version)--for example, 
+it is multilingual, multiplatform, and highly configurable. It 
+incorporates all the features of the existing system, and is backwards 
+compatible: that is, it can build and run existing collections without 
+modification. Written in Java, it is structured as a network of 
+independent modules that communicate using XML: thus it runs in a 
+distributed fashion and can be spread across different servers as 
+necessary. This modular design increases the flexibility and 
+extensibility of Greenstone. The new version is expected to be 
+available for experimental use by 23 December 2003. An initial design for 
+the system is outlined in "The design of Greenstone 3: An agent based 
+dynamic digital library" (download <a href="http://www.greenstone.org/manuals/gs3desig.pdf">PDF</a>).
+</xsl:template>
+
+
+  <xsl:template name="textcreditstitle">credits</xsl:template>
+
+  <xsl:template name="textwhoswho">
+The Greenstone software is a collaborative effort between many
+people. Rodger McNab and Stefan Boddie are the principal architects and
+implementors.  Contributions have been made by David Bainbridge, George
+Buchanan, Michael Dewsnip, Katherine Don, Hong Chen, Elke Duncker, 
+Carl Gutwin, Geoff Holmes, John McPherson, Craig Nevill-Manning, 
+Dynal Patel, Gordon Paynter, Bernhard Pfahringer, Todd
+Reed, Bill Rogers, John Thompson, and Stuart Yeates.
+Other members of the New Zealand Digital Library project provided advice 
+and inspiration in the design of
+the system: Mark Apperley, Sally Jo Cunningham, Matt Jones, Steve Jones, 
+Te Taka Keegan, Michel Loots, Malika Mahoui, Gary Marsden, Dave Nichols 
+and Lloyd Smith. We would also like to
+acknowledge all those who have contributed to the GNU-licensed packages
+included in this distribution: MG, GDBM, PDFTOHTML, WGET, WVWARE and XLHTML.
+  </xsl:template>
+
+  
+</xsl:stylesheet>
Index: /greenstone3/trunk/web/interfaces/nzdl/transform/gsdl.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/nzdl/transform/gsdl.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/nzdl/transform/gsdl.xsl	(revision 14125)
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+
+  <xsl:include href="style.xsl"/>
+  <xsl:include href="gsdl-text.xsl"/>
+  <xsl:include href="home-text.xsl"/>
+  <xsl:include href="page-common.xsl"/>
+
+  <xsl:output method="html"/>  
+
+ <xsl:template name="pageTitle">
+    <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'nzdl')"/>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+  <xsl:template match="pageResponse">
+    <center>
+    <xsl:call-template name="genericPageBanner"><xsl:with-param name='text'><xsl:call-template name="aboutgs"/></xsl:with-param></xsl:call-template>
+    </center>
+    <p />
+    <table border='0' cellspacing='0' cellpadding='0'>
+      <tr>
+	<td valign='top' align='center'><xsl:call-template name="imagegreenstone"/></td>
+	<td valign='top'><xsl:call-template name="textgreenstone1"/>
+	  <br /><br />
+	</td>
+      </tr>
+      <tr>
+	<td valign='top' align='center'>
+	  <h2><a href="http://nzdl.org">nzdl.org</a></h2>
+	</td>
+	<td valign='top'><xsl:call-template name="textgreenstone2"/>
+	  <br /><br />
+	</td>
+      </tr>
+      <tr>
+	<td valign='top' align='center'>
+	  <h2><xsl:call-template name="textplatformtitle"/></h2>
+	</td>
+	<td valign='top'><xsl:call-template name="textgreenstone3"/>
+	  <br /><br />
+	</td>
+      </tr>
+      <tr>
+	<td valign='top' align='center'>
+	  <a href="http://nzdl.org/hdl"><img border='0' width='101' height='100' src="interfaces/nzdl/images/hdlimg.jpg"/></a>
+	</td>
+	<td valign='top'>
+	  <xsl:call-template name="textgreenstone4"/>
+	  <br /><br />
+	</td>
+      </tr>
+      <tr>
+	<td valign='top' align='center'>
+	  <h2><xsl:call-template name="textcustomisationtitle"/></h2>
+	</td>
+	<td valign='top'><xsl:call-template name="textgreenstone5"/>
+	  <br /><br />
+	</td>
+      </tr>
+      <tr>
+	<td valign='top' align='center'>
+	  <h2><a href="http://www.greenstone.org/english/docs.html"><xsl:call-template name="textdocumentationtitle"/></a></h2>
+	</td>
+	<td valign='top'><xsl:call-template name="textdocuments"/>
+	<br /><br />
+	</td>
+      </tr>
+      <tr>
+	<td valign='top' align='center'>
+	  <h2><xsl:call-template name="textmailinglisttitle"/></h2>
+	</td>
+	<td valign='top'><xsl:call-template name="textmailinglist"/>
+	  <br /><br />
+	</td>
+      </tr>
+      <tr>
+	<td valign='top' align='center'>
+	  <h2><xsl:call-template name="textbugstitle"/></h2>
+	</td>
+	<td valign='top'><xsl:call-template name="textreport"/>
+	  <br /><br />
+	</td>
+      </tr>
+       <tr>
+         <td valign='top' align='center'>
+	   <h2><xsl:call-template name="textgs3title"/></h2>
+	 </td>
+	 <td valign='top'><xsl:call-template name="textgs3"/>
+	   <br /><br />
+	 </td>
+      </tr>
+
+      <tr>
+	<td valign='top' align='center'>
+	  <h2><xsl:call-template name="textcreditstitle"/></h2>
+	</td>
+	<td valign='top'><xsl:call-template name="textwhoswho"/>
+	</td>
+      </tr>
+    </table>
+    <center>
+    <p /><xsl:call-template name="dividerBar"/>
+    <xsl:call-template name="greenstone_info"/>
+    <xsl:call-template name="nzdlpagefooter"/>
+    </center>
+  </xsl:template>
+
+</xsl:stylesheet>
+
Index: /greenstone3/trunk/web/interfaces/nzdl/transform/home-text.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/nzdl/transform/home-text.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/nzdl/transform/home-text.xsl	(revision 14125)
@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  extension-element-prefixes="java">
+
+  <!--<xsl:include href="style.xsl"/>-->
+<xsl:template name="textpagetitle">New Zealand Digital Library</xsl:template>
+<xsl:template name="textprojhead">The New Zealand Digital Library Project</xsl:template>
+
+<xsl:template name="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 interfaces 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!
+</xsl:template>
+
+<xsl:template name="titlesoftwareinfo">The Greenstone software</xsl:template>
+
+<xsl:template name="textsoftwareinfo">
+<p />
+The <a href="http://www.greenstone.org">Greenstone Digital Library software</a> 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>To subscribe to the Greenstone mailing list, go to <a 
+href="https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users">https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users</a>.</p>
+
+<p align='right'/>
+<a href="{$library_name}?a=p&amp;sa=gsdl">More...</a>
+</xsl:template>
+
+<xsl:template name="titleresearchinfo">Our research</xsl:template>
+
+<xsl:template name="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="http://www.nzdl.org/html/research.html">More...</a>
+</xsl:template>
+
+<xsl:template name="titleaffiliateinfo">Our affiliates</xsl:template>
+
+<xsl:template name="textaffiliatehumaninfo">
+<p />
+<a href="http://humaninfo.org">Human Info NGO</a>
+is a registered charity responsible for the
+provision of universal low-cost
+information access through co-operation between UN Agencies,
+universities and NGOs. Human Info NGO collaborates extensively
+with the NZDL project, and use the Greenstone software. 
+</xsl:template>
+
+<xsl:template name="textaffiliateunesco">
+<p />
+<a href="http://www.unesco.org">United Nations Educational, Scientific and Cultural Organization</a>.
+The dissemination of educational, scientific and cultural information
+throughout the world, and particularly its availability
+</xsl:template>
+
+<xsl:template name="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.
+</xsl:template>
+
+<xsl:template name="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.
+</xsl:template>
+
+<xsl:template name="textaboutgreenstone">
+<p />Greenstone is a suite of software for building and distributing digital
+library collections. It provides a new way of organizing information and
+publishing it on the Internet or on CD-ROM.  Greenstone is produced by the
+<b>New Zealand Digital Library Project</b> at the <b>University of
+Waikato</b>, and developed and distributed in cooperation with
+<b>UNESCO</b> and the <b>Human Info NGO</b>.  It is open-source
+software, available from <a href="http://greenstone.org">http://greenstone.org</a> under the terms of
+the GNU General Public License.
+
+<p />The aim of the software is to empower users, particularly in
+universities, libraries, and other public service institutions, to
+build their own digital libraries.  Digital libraries are radically
+reforming how information is disseminated and acquired in UNESCO's
+partner communities and institutions in the fields of education,
+science and culture around the world, and particularly in developing
+countries.  We hope that this software will encourage the effective
+deployment of digital libraries to share information and place it in
+the public domain.
+
+
+<p />This software is developed and distributed as an international
+cooperative effort established in August 2000 among three parties.
+
+<table border="0">
+<tr valign="top">
+<td>
+<a href="http://nzdl.org"><b>New Zealand Digital Library Project at the University of Waikato</b></a>
+<br />
+Greenstone software grew out of this project, and this initiative
+has been endorsed by the Communication Sub-Commission of the New
+Zealand National Commission for UNESCO as part of New Zealand's
+contribution to UNESCO's programme.
+</td>
+<td></td>
+</tr>
+<tr valign="top">
+<td>
+<a href="http://www.unesco.org"><b>United Nations Educational, Scientific and Cultural Organization</b></a>
+<br />
+The dissemination of educational, scientific and cultural information
+throughout the world, and particularly its availability in developing
+countries, is central to UNESCO's goals as pursued within its
+intergovernmental Information for All Programme, and appropriate,
+accessible information and communication technology is seen as an important
+tool in this context.
+</td>
+<td><a href="http://www.unesco.org"><img src="interfaces/nzdl/images/unesco.gif" border="0"/></a></td>
+</tr>
+<tr valign="top">
+<td>
+<a href="http://humaninfo.org"><b>The Human Info NGO, based in Antwerp, Belgium</b></a>
+<br />
+This project works with UN agencies and other NGOs, and has established
+a worldwide reputation for digitizing documentation of interest to
+human development and making it widely available, free of charge to
+developing nations and on a cost-recovery basis to others.
+</td>
+<td><a href="http://humaninfo.org"><img src="interfaces/nzdl/images/ghproj2.jpg" border="0"/></a></td>
+</tr>
+</table>
+</xsl:template>
+
+  <xsl:template name="textimagegreenstone">Greenstone Digital Library Software</xsl:template>
+  
+  <xsl:template name="nzdlpagefooter">
+      <p /><xsl:call-template name="dividerBar"/>
+      <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
+    </xsl:template>
+    
+</xsl:stylesheet>
Index: /greenstone3/trunk/web/interfaces/nzdl/transform/home.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/nzdl/transform/home.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/nzdl/transform/home.xsl	(revision 14125)
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+
+  <xsl:include href="style.xsl"/>
+  <xsl:include href="home-text.xsl"/>
+  <xsl:include href="page-common.xsl"/>
+
+  <xsl:output method="html"/>  
+
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="util:getInterfaceText($interface_name, /page/@lang, 'nzdl')"/>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+  <xsl:template match="pageResponse">
+    <xsl:call-template name="nzdlPageBanner"/>     
+    <center>
+    <xsl:apply-templates select="collectionList"/>
+    </center>
+    <center><xsl:call-template name="dividerBar"/></center>    
+    <p />
+    <center><h2><xsl:call-template name="textprojhead"/></h2></center>
+    
+    <table border='0' cellpadding='5'>
+      <xsl:call-template name="project_info"/>
+      <xsl:call-template name="software_info"/>
+      <xsl:call-template name="research_info"/>
+      <xsl:call-template name="affiliate_info"/>
+    </table>
+    <center>
+      <xsl:call-template name="dividerBar"/>
+      <xsl:call-template name="greenstone_info"/>
+      <p />
+      <xsl:call-template name="nzdlpagefooter"/> 
+      <br />September 2003
+    </center>
+  </xsl:template>
+
+  <xsl:template name="project_info">
+    <tr valign='top'>
+      <td>
+	<table><tr valign='middle'><td><img src="interfaces/nzdl/images/gbull.gif"/></td><td><a href="mailto:greenstone@cs.waikato.ac.nz">Feedback</a></td></tr></table>
+	<table><tr valign='middle'><td><img src="interfaces/nzdl/images/gbull.gif"/></td><td><a href="http://www.nzdl.org/html/people.html">People</a></td></tr></table>
+	<table><tr valign='middle'><td><img src="interfaces/nzdl/images/gbull.gif"/></td><td><a href="http://greenstone.cs.uct.ac.za/gsdl/cgi-bin/library">African Digital Library Centre</a></td></tr></table>
+<table><tr valign='middle'><td><img src="interfaces/nzdl/images/gbull.gif"/></td><td><a href="http://sadl.uleth.ca">Southern Alberta Digital Library Centre</a></td></tr></table>
+      </td>
+      <td><xsl:call-template name="textprojinfo"/></td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template name="software_info">
+    <tr>
+      <td></td>
+      <th align='left'><xsl:call-template name="titlesoftwareinfo"/></th>
+    </tr>
+    <tr valign='top'>
+      <td>
+	<table><tr valign='middle'><td><img src="interfaces/nzdl/images/gbull.gif"/></td><td><a href="{$library_name}?a=p&amp;sa=gsdl">About<br />Greenstone 2</a></td></tr></table>
+	<table><tr valign='middle'><td><img src="interfaces/nzdl/images/gbull.gif"/></td><td><a href="http://www.greenstone.org/english/docs.html">Greenstone 2<br />Documentation</a></td></tr></table>
+      </td>
+      <td><xsl:call-template name="textsoftwareinfo"/></td>
+    </tr>
+  </xsl:template>
+  
+  <xsl:template name="research_info">
+    <tr>
+    <td></td>
+    <th align='left'><xsl:call-template name="titleresearchinfo"/></th>
+  </tr>
+    <tr valign='top'>
+      <td>
+	<table><tr valign='middle'><td><img src="interfaces/nzdl/images/gbull.gif"/></td><td><a href="http://www.nzdl.org/html/research.html">Research</a></td></tr></table>
+	<table><tr valign='middle'><td><img src="interfaces/nzdl/images/gbull.gif"/></td><td><a href="http://www.nzdl.org/html/projects.html">Projects</a></td></tr></table>
+	<table><tr valign='middle'><td><img src="interfaces/nzdl/images/gbull.gif"/></td><td><a href="http://www.nzdl.org/html/software.html">Software<br />Downloads</a></td></tr></table>
+	<table><tr valign='middle'><td><img src="interfaces/nzdl/images/gbull.gif"/></td><td><a href="http://www.cs.waikato.ac.nz/~nzdl/publications/">Publications</a></td></tr></table>
+      </td>
+      <td><xsl:call-template name="textresearchinfo"/></td>
+    </tr>
+    
+<!--    <tr valign='top'>
+      <td>
+	<table><tr valign='middle'><td><img src="interfaces/nzdl/images/gbull.gif"/></td><td><a href="http://nzdl2.cs.waikato.ac.nz/cgi-bin/zdemo/library">Z39.50<br />demo</a></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>-->
+  </xsl:template>
+
+  <xsl:template name="affiliate_info">
+    <tr>
+      <td></td>
+      <th align='left'><xsl:call-template name="titleaffiliateinfo"/></th>
+    </tr>
+    <tr valign='top'>
+      <td>
+	<img src="interfaces/nzdl/images/ghproj.jpg" alt="Human Info NGO" width='100' height='90'/>
+      </td>
+      <td><xsl:call-template name="textaffiliatehumaninfo"/></td>
+    </tr>
+    <tr valign='top'>
+      <td><img src="interfaces/nzdl/images/unesco.gif" alt="UNESCO" width='100' height='90' />
+      </td>
+      <td><xsl:call-template name='textaffiliateunesco'/></td>
+      </tr>
+  </xsl:template>
+  
+  <xsl:template match="collection">
+  <xsl:param name="extraArgs"/>
+    <xsl:variable name="ct"><xsl:choose><xsl:when test="metadataList/metadata[@name='buildType']='mgpp'">1</xsl:when><xsl:otherwise>0</xsl:otherwise></xsl:choose></xsl:variable>
+    <p />
+    <a href="{$library_name}?a=p&amp;sa=about&amp;c={@name}&amp;ct={$ct}{$extraArgs}">
+      <img width="150" border="1">
+	<xsl:attribute name="src">
+	  <xsl:value-of select="metadataList/metadata[@name='httpPath']"/>/images/<xsl:choose><xsl:when test="displayItem[@name='smallicon']"><xsl:value-of select="displayItem[@name='smallicon']"/></xsl:when><xsl:otherwise><xsl:value-of select="displayItem[@name='icon']"/></xsl:otherwise></xsl:choose>
+	</xsl:attribute>
+	<xsl:attribute name="alt">
+	  <xsl:value-of select="displayItem[@name='name']"/>
+	</xsl:attribute>
+      </img>
+    </a>
+    <p />
+  </xsl:template> 
+
+
+  <xsl:template match="collectionList">
+    <center>
+      <xsl:call-template name="dividerBar"><xsl:with-param name="text">Humanitarian and UN collections</xsl:with-param></xsl:call-template>
+      <p /><xsl:call-template name="collectfao"/>
+      <xsl:call-template name="dividerBar"><xsl:with-param name="text">Demonstration collections</xsl:with-param></xsl:call-template> 
+      <p /><xsl:call-template name="collectrest"/>
+    </center>
+  </xsl:template>
+
+  <xsl:template name="collectfao">
+    <table width="537">
+      <tr valign='top'>
+	<td align='center'>
+	  <p /><xsl:apply-templates select="collection[@name='hdl']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='fnl']"/>
+ 	  <p /><xsl:apply-templates select="collection[@name='envl']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='aginfo']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='gtz']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='cdl']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='edudev']"/>
+	  <p /><xsl:apply-templates select="collection[@name='nigeria']"/>
+	  <p /><xsl:apply-templates select="collection[@name='safem']"/>
+	  <p />firstaid<xsl:apply-templates select="collection[@name='firstaid']"/>
+	</td>
+	<td align='center'>
+	  <p /><xsl:apply-templates select="collection[@name='mhl']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='fnl1_1']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='paho']"/>
+	  <p /><xsl:apply-templates select="collection[@name='unesco']"/>
+          <p /><xsl:apply-templates select="collection[@name='muster']"/>
+	  <p /><xsl:apply-templates select="collection[@name='unescoen']"/>
+	  <p /><xsl:apply-templates select="collection[@name='dfid']"/>	
+	  <p /><xsl:apply-templates select="collection[@name='ewf']"/>	
+	  <p /><xsl:apply-templates select="collection[@name='fi1998']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='faodocs']"/>  
+	</td>
+	<td align='center'> 
+	  <p /><xsl:apply-templates select="collection[@name='ccgi']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='fnl2.2']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='who']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='tulane']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='unaids']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='aedl']"/>
+	  <p /><xsl:apply-templates select="collection[@name='whoedm']"/>
+	  <p /><xsl:apply-templates select="collection[@name='helid']"/>
+	  <p /><xsl:apply-templates select="collection[@name='ipc']"/>	
+	  <p /><xsl:apply-templates select="collection[@name='povsem']"/>
+	</td>
+      </tr>
+    </table>
+  </xsl:template>
+  
+
+  <xsl:template name="collectrest">
+    <table width='537'>
+      <tr valign='top'>
+	<td align='center'>
+	  <p /><xsl:apply-templates select="collection[@name='acrodemo']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='niupepa']"/> 
+	  <p />howto DL<xsl:apply-templates select="collection[@name='howto']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='arabic']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='chinese']">
+	  <xsl:with-param name="extraArgs">&amp;l=zh</xsl:with-param>
+	  </xsl:apply-templates>	 
+ 	  <p /><xsl:apply-templates select="collection[@name='folktale']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='demooai']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='tidbits']"/> 
+	</td>
+	<td align='center'>
+	  <p />meldex<xsl:apply-templates select="collection[@name='meldex']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='wordpdf']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='musvid']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='gberg']"/> 
+ 	  <p /><xsl:apply-templates select="collection[@name='allshake']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='aircraft']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='csbib']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='coltbib']">
+	  <xsl:with-param name="extraArgs">&amp;qt=1</xsl:with-param>
+	  </xsl:apply-templates> 
+	</td>
+	<td align='center'>
+	  <p /><xsl:apply-templates select="collection[@name='cstr']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='gsarch']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='ohist']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='hcibib']"/> 
+ 	  <p /><xsl:apply-templates select="collection[@name='whist']"/> 
+	  <p /><xsl:apply-templates select="collection[@name='beowulf']"/>
+	  <p /><xsl:apply-templates select="collection[@name='tcc']"/>
+	  <p /><xsl:apply-templates select="collection[@name='jair']"/>  
+	</td>
+      </tr>
+    </table>
+  </xsl:template>
+  
+</xsl:stylesheet>  
+
+
+
+
Index: /greenstone3/trunk/web/interfaces/nzdl/transform/page-common.xsl
===================================================================
--- /greenstone3/trunk/web/interfaces/nzdl/transform/page-common.xsl	(revision 14125)
+++ /greenstone3/trunk/web/interfaces/nzdl/transform/page-common.xsl	(revision 14125)
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+  <xsl:template name="greenstone_info">
+    <p />
+    <table>
+      <tr valign='top'>
+	<td><xsl:call-template name="textpoem"/></td>
+	<td><xsl:call-template name="imagegreenstone"/></td>
+      </tr></table>
+    <p />
+    <table><tr><td><xsl:call-template name="textgreenstone"/></td></tr></table>
+  </xsl:template>
+
+</xsl:stylesheet>
Index: /greenstone3/trunk/web/search.html
===================================================================
--- /greenstone3/trunk/web/search.html	(revision 14125)
+++ /greenstone3/trunk/web/search.html	(revision 14125)
@@ -0,0 +1,224 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<html>
+<head>
+<title>AJAX GS3 Search</title>
+<META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE">
+<META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE">
+<style type="text/css">
+<!-- 
+BODY, P, LI { font-family: sans-serif; } 
+H2 {font-size: 90%;}
+BUTTON {font-size: 0.8em; margin: 0 1em; color: red;}
+#searchArea {background-color:white; }
+#resultArea {background-color:white; padding: 0em 0em;}
+#resultSummary {font-size: 80%; padding: 0.2 em 0.2em;}
+#resultSummary P {padding: 0.2em 0.3em;}
+#query {padding: 0.1em 0.5em; width: 400px; height: 150px; background-color:#d3d3d3;}
+#timing {float:right; width: 250px; border: thin solid #d3d3d3; padding: 0.2em 0.2em; display: none;}
+#resultList {	list-style-image: none; 
+						list-style-type: square;
+						font-size: 85%; padding: 1em 0em 1em 2em;}
+#resultList LI {padding: 0.3em 0em; }
+-->
+</style>
+<script type="text/javascript" src="xmlextras.js">
+</script> 
+<script type="text/javascript" src="gs_ajax_utils.js">
+</script> 
+<script type="text/javascript">
+<!--
+
+localsiteServerAddress = "/gsdl3/services/localsite";
+libraryAddress = "/gsdl3/library";
+function loadAsync(sUri, SOAPMessage, callbackFunction) {
+   var xmlHttp = XmlHttp.create();
+   var async = true;
+   xmlHttp.open("POST", sUri, async);
+   xmlHttp.onreadystatechange = function () {
+      if (xmlHttp.readyState == 4){
+		var result = xmlHttp.responseText;
+			//getTitle2(xmlHttp.responseXML, xmlHttp.responseText);
+			eval(callbackFunction);
+    }     
+   }
+   xmlHttp.setRequestHeader("SOAPAction", " ");
+   xmlHttp.setRequestHeader("Content-Type", "Content-Type: text/xml; charset=utf-8");
+ 
+   xmlHttp.send(SOAPMessage);
+}
+
+
+function ajaxSearch() {
+
+searchStartTime = new Date();
+
+resultList = document.getElementById('resultList');
+removeAllChildren(resultList);
+resultSummary = document.getElementById('resultSummary');
+removeAllChildren(resultSummary);
+
+/*
+for (i=0; i < 10; i++) {
+    listElement = document.createElement('li');
+    anchor = document.createElement('a');
+    anchor.setAttribute('href', url);
+    anchor.appendChild(document.createTextNode(  text));
+    listElement.appendChild(anchor);
+    resultList.appendChild(listElement);
+}
+*/
+
+queryText = document.getElementById('queryText').value;
+
+maxdocs = newElementAtt('param', '', new Array('name', 'value'), new Array('maxDocs', '100') ) ;
+level = newElementAtt('param', '', new Array('name', 'value'), new Array('level', 'Sec') ) ;
+indexValue = newElementAtt('param', '', new Array('name', 'value'), new Array('index', 'ZZ') ) ;
+matchMode = newElementAtt('param', '', new Array('name', 'value'), new Array('matchMode', 'some') ) ;
+query = newElementAtt('param', '', new Array('name', 'value'), new Array('query', queryText) ) ;
+caseValue = newElementAtt('param', '', new Array('name', 'value'), new Array('case', '1') ) ;
+sortBy = newElementAtt('param', '', new Array('name', 'value'), new Array('sortBy', '1') ) ;
+stem = newElementAtt('param', '', new Array('name', 'value'), new Array('stem', '1') ) ;
+
+
+paramList = newElement('paramList', maxdocs + level + indexValue + matchMode + query + caseValue + sortBy + stem);
+
+collection = document.getElementById('collectionText').value;
+request = newElementAtt('request', paramList, new Array('lang', 'to', 'type', 'uid'), new Array('en',collection + '/TextQuery', 'process', '1'  ) );
+message = newElement('message', request );
+soapMessage = messageToSOAP(message);
+loadAsync(localsiteServerAddress, soapMessage, 'getResults(xmlHttp.responseXML)');
+}
+
+function getResults(xmlDoc) {
+idsReturnedTime = new Date();
+    metadataList = xmlDoc.getElementsByTagName('metadata');
+    for (i=0; i < metadataList.length; i++) {
+    	metadata = metadataList[i];
+    	if (isElement(metadata)) {
+		  nameAtt = metadata.getAttribute('name')
+    		if ( nameAtt == 'numDocsMatched') {
+    			numDocsMatched = getText(metadata);
+    		}
+    		if (nameAtt == 'numDocsReturned') {
+    			numDocsReturned = getText(metadata);
+    		}
+    		if (nameAtt  == 'query') {
+    			query = getText(metadata);
+    		}
+    	}
+    }
+    
+    resultSummary = document.getElementById('resultSummary');
+    para = document.createElement('p');
+    para.appendChild(document.createTextNode('Query: ' + query + ' Number of Matching Docs: ' + numDocsMatched + ' Number of returned documents: ' + numDocsReturned));
+    resultSummary.appendChild(para);
+    
+    documentNodeList = xmlDoc.getElementsByTagName('documentNode');
+    	
+    for (i=0; i < documentNodeList.length; i++) {
+    	documentNode = documentNodeList[i];
+    	if (isElement(documentNode)) {
+    		docIDArray[i] = documentNode.getAttribute('nodeID');
+    	}
+    }
+   
+    var docsList = '';
+    for (i=0; i < docIDArray.length; i++) {
+    	docsList += newElementAtt1('documentNode', '', 'nodeID', docIDArray[i]);
+    }
+	
+    docNodeList = newElement('documentNodeList', docsList);
+	collection = document.getElementById('collectionText').value;
+    param = newElementAtt('param', '', new Array('name', 'value'), new Array('metadata', 'Title') );
+    paramList = newElement('paramList', param);
+	request = newElementAtt('request', paramList + docNodeList, new Array('lang', 'to', 'type', 'uid'), new Array('en',collection + '/DocumentMetadataRetrieve', 'process', '1'  ) );
+    message = newElement('message', request ); 
+    soapMessage = messageToSOAP(message);
+	//alert(soapMessage);
+    loadAsync(localsiteServerAddress, soapMessage, 'displayResults(xmlHttp.responseXML)');
+}
+
+
+function displayResults(xmlDoc) {
+	metadataReturnedTime = new Date();
+	url1 = libraryAddress+'?a=d&d=';
+	url2 = '&c=' + document.getElementById('collectionText').value + '&dt=hierarchy';
+	resultList = document.getElementById('resultList');
+    metadataList = xmlDoc.getElementsByTagName('metadata');
+	//alert('in display results ' + metadataList.length + xmlDoc.xml);
+        for (i=0; i < metadataList.length; i++) {
+			  //alert('in display results ' + i);
+        	metadata = metadataList[i];
+        	if (isElement(metadata)) {
+        		if (metadata.getAttribute('name') == 'Title') {
+					
+          		  listElement = document.createElement('li');
+                anchor = document.createElement('a');
+                anchor.setAttribute('href', url1 + docIDArray[i] + url2);
+                anchor.appendChild(document.createTextNode(getText(metadata)) );
+                listElement.appendChild(anchor);
+                resultList.appendChild(listElement);
+        		}   		
+        	}
+        }
+			finishedTime = new Date();
+			displayTime();
+			
+}
+
+function displayTime() {
+searchStart = document.getElementById('searchStart');
+idsReturned = document.getElementById('idsReturned');
+metadataReturned = document.getElementById('metadataReturned');
+//removeAllChildren(searchStart);
+//searchStart.appendChild(document.createTextNode(searchStartTime.getMilliseconds() + ' ms'))
+removeAllChildren(idsReturned);
+idsReturned.appendChild(document.createTextNode(idsReturnedTime.getMilliseconds() - searchStartTime.getMilliseconds()+ ' ms'))
+removeAllChildren(metadataReturned);
+metadataReturned.appendChild(document.createTextNode(metadataReturnedTime.getMilliseconds() - idsReturnedTime.getMilliseconds()+ ' ms'))
+//alert(searchStartTime.getMilliseconds() + ' ' + idsReturnedTime.getMilliseconds() + ' ' + metadataReturnedTime.getMilliseconds() + ' ' + ' ' + finishedTime.getMilliseconds());
+}
+
+
+var docIDArray = new Array();
+var searchStartTime, idsReturnedTime, metadataReturnedTime, finishedTime;
+
+
+
+
+// -->
+</script>
+</head>
+<body>
+
+
+
+<div id="searchArea">
+
+<div id="timing">
+<p><strong>Timing</strong></p>
+<table border="0" cellpadding="0" cellspacing="0" summary="">
+<!-- <tr><td>Search started:</td><td id="searchStart"></td></tr> -->
+<tr><td>Time to get IDs:</td><td id="idsReturned"></td></tr>
+<tr><td>Time to get Metadata:</td><td id="metadataReturned"></td></tr>
+</table>
+</div> 
+
+<div id="query"><h2>Search a Greenstone 3 Collection</h2>
+<form action="">
+<p><label for="collectionText">GS3 Collection:</label>
+<input id="collectionText" type="text" value="gs2mgppdemo"/></p>
+
+<p><input id="queryText" type="text" /><input id="searchButton" type="submit" value="Search" onclick="ajaxSearch();return false;"></input></p>
+
+</form></div>
+</div>
+
+<div id="resultArea">
+<div id="resultSummary"></div>
+<ul id="resultList"></ul>
+</div>
+ 
+</body>
+</html>
Index: /greenstone3/trunk/web/sites/gateway/siteConfig.xml
===================================================================
--- /greenstone3/trunk/web/sites/gateway/siteConfig.xml	(revision 14125)
+++ /greenstone3/trunk/web/sites/gateway/siteConfig.xml	(revision 14125)
@@ -0,0 +1,11 @@
+<siteConfig 
+  xmlns:gsf='http://www.greenstone.org/greenstone3/schema/ConfigFormat' 
+  xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
+  <siteList localSiteName="gateway">
+    <!-- a site element needs name and type, then either an addess attribute where the URL of the server can be accessed, or a localSite attribute, which specifies to use the local server on a local site. This second method is just for testing. The address of a SOAP server deployed by axis in greenstone would be like http://{tomcat_server}:{tomcat_port}/gsdl3/services/{site_name} -->
+    <site name="localsite" localSite="localsite" type="soap"/>
+  </siteList>
+  <serviceClusterList/>
+  <serviceRackList/>
+</siteConfig>
+
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/README
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/README	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/README	(revision 14125)
@@ -0,0 +1,57 @@
+The Sample XML texts collection.
+
+This README provides directions on how to rebuild the collection if necessary, 
+and how to create a new collection using this method.
+
+Building the gberg collection (linux):
+
+Starting from the gberg directory (where this README file is located):
+cd java
+javac *.java
+cd ..
+java -classpath $CLASSPATH:./java BuildXMLColl $GSDL3HOME/web/sites/localsite gberg
+mv building index
+cp etc/buildConfig.xml index
+cp import/*.dtd $GSDL3HOME/resources/dtd/
+
+The building process:
+
+There are two stages, import and build.
+Importing goes through the xml documents in the import directory and adds 
+gs3:id attributes to indexable nodes. Building makes another pass though the 
+documents, indexing any indexable nodes, and assigning them node ids. Node 
+ids are made up of several parts: document id, scope, tag name, gs3:id. 
+Document id refers to the work, and is generated from the original document 
+filename. For example, origin.xml becomes origin. The scope part is optional. 
+Tag name is the name of the node that is to be indexed, and gs3:id is its id.
+
+The class XMLTagInfo provides two methods, isIndexable and isScopable, and is 
+used to determine which tags provide scope, and which tags should be indexed. 
+This is the only part of the build code that is specific to the documents in 
+the collection.
+
+Indexable nodes are those that should be indexed individually. When a search 
+is done, these are the units that will be returned. For instance, suppose a 
+collection contains books with chapters and sections of chapters. To have 
+searching and retrieval at chapter level, the chapter nodes would be made 
+indexable. Alternatively, making the section nodes indexable would provide 
+searching at the smaller section level instead.
+
+Scopable nodes are not necessarily indexed, but are recorded as part of the 
+id as a scope. This is to speed up searching for the appropriate tag during 
+retrieval. Scopeable tags should only occur once per document.
+
+Building other collections:
+
+To use the java building stuff for other XML document collections, you can 
+just modify the XMLTagInfo.java file to include the appropriate tag names for 
+your XML documents. Then put import documents into the import directory, and 
+run the BuildXMLColl program as above. Configuration files will need to be 
+created for the collection (etc/collectionConfig.xml and 
+index/buildConfig.xml).
+
+The Greenstone runtime software has problems locating DTDs, so any DTDs for 
+your collection should be placed in the collection's resources directory.
+If DTD files are shared between collections, they can go into the 
+WEB-INF/classes directory (in gsdl3/web or tomcat/webapps/gsdl3, depending on 
+your setup).
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/etc/buildConfig.xml
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/etc/buildConfig.xml	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/etc/buildConfig.xml	(revision 14125)
@@ -0,0 +1,16 @@
+<buildConfig xmlns:gsf="http://www.greenstone.org/configformat" >
+  <metadataList>
+    <metadata name="numDocs">4</metadata>
+    <metadata name="buildType">lucene</metadata>
+  </metadataList>
+  <serviceRackList>
+    <serviceRack name="GutBookRetrieve">
+      <paramList>
+	<param name="tocXSLT" value="produce-toc"/>
+	<param name="documentEncoding" value="UTF-8"/>
+	<param name="documentRootTag" value="book"/>
+      </paramList>
+    </serviceRack>
+    <serviceRack name="LuceneSearch"/>
+  </serviceRackList>
+</buildConfig>
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/etc/collectionConfig.xml
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/etc/collectionConfig.xml	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/etc/collectionConfig.xml	(revision 14125)
@@ -0,0 +1,61 @@
+<collectionConfig 
+  xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat" 
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
+  <metadataList>
+    <metadata name="creator">greenstone@cs.waikato.ac.nz</metadata>
+  </metadataList>
+  <displayItemList>
+    <displayItem name='name' lang='en'>Sample XML Texts Collection</displayItem>
+    <displayItem name='icon' lang='en'>gberg.gif</displayItem>
+    <displayItem name='smallicon' lang='en'>gbergsm.gif</displayItem>
+    <displayItem name='description' lang='en'>
+&lt;p&gt;This collection is designed to demonstrate some of the flexibility of the Greenstone 3 architecture. Collections are not restricted to those built using the standard building process, but rather can be anything you want, as long as suitable services are provided.&lt;/p&gt; 
+&lt;p&gt; This collection contains 4 documents obtained from the &lt;a href="http://gutenberg.net/"&gt;Gutenberg project&lt;/a&gt;. Project Gutenberg documents are marked up in XML, and come with DTDs and CSS stylesheets. The collection has not been built using either Greenstone2 or Greenstone3 style building. Instead, simple java programs using the Lucene API have been created to do the indexing, and document retrieval is simply done from the original (actually slightly modified) XML documents. A description of the building process can be found in the &lt;a href="sites/localsite/collect/gberg/README"&gt;README&lt;/a&gt; file for this collection.&lt;/p&gt; 
+&lt;p&gt; This collection has a different appearance to standard collections, accomplished through the use of custom XSLT files, found in the transform directory of the collection. The 'about' page for the collection shows a list of all the documents. This is achieved by using a new about.xsl file. Document display is quite different for this collection: the display can be either table of contents style, or text style. Two new xslts were written to handle the two display types. A new document action also had to be created (XMLDocumentAction), and the interface config file was altered to map the xd action code to this new Action class.&lt;/p&gt; 
+&lt;p&gt; &amp;lt;action name='xd' class='XMLDocumentAction'&amp;gt;&lt;br/&gt;
+&amp;nbsp;&amp;nbsp;&amp;lt;subaction name='toc' xslt='document-toc.xsl'/&amp;gt;&lt;br/&gt;
+&amp;nbsp;&amp;nbsp;&amp;lt;subaction name='text' xslt='document-text.xsl'/&amp;gt;&lt;br/&gt;
+&amp;lt;/action&amp;gt;&lt;/p&gt; 
+&lt;p&gt;The collection uses a generic Greenstone Lucene search service, and a specific retrieval service class, GutBookRetrieve. This extends the generic XMLRetrieve serviceRack to handle metadata extraction for the Gutenberg documents.&lt;/p&gt; 
+&lt;p&gt;The collection configuration file can be seen &lt;a href="sites/localsite/collect/gberg/etc/collectionConfig.xml"&gt;here&lt;/a&gt;, and the building configuration file can be seen &lt;a href="sites/localsite/collect/gberg/index/buildConfig.xml"&gt;here&lt;/a&gt;.&lt;/p&gt;
+</displayItem>
+  </displayItemList>
+  <search>
+    <format>
+      <gsf:template match="documentNode">
+	<xsl:param name="collName"/>
+	<xsl:param name="serviceName"/>
+	<td>
+	<b><a href="{$library_name}?a=xd&amp;sa=text&amp;c={$collName}&amp;d={@nodeID}&amp;p.a=q&amp;p.s={$serviceName}"><xsl:choose><xsl:when test="metadataList/metadata[@name='Title']"><gsf:metadata name="Title"/></xsl:when><xsl:otherwise>(section)</xsl:otherwise></xsl:choose></a></b> from <b><a href="{$library_name}?a=xd&amp;sa=toc&amp;c={$collName}&amp;d={@nodeID}.rt&amp;p.a=q&amp;p.s={$serviceName}"><gsf:metadata name="Title" select="root"/></a></b>
+	</td>
+      </gsf:template>
+    </format>
+  </search>
+  <browse/>
+  <documentList>
+    <document name='origin'>
+      <metadataList>
+	<metadata name='Title'>On the Origin of Species</metadata>
+	<metadata name="Author">Charles Darwin</metadata>
+      </metadataList>
+    </document>
+    <document name='iliad'>
+      <metadataList>
+	<metadata name='Title'>The Iliad</metadata>
+	<metadata name="Author">Homer</metadata>
+      </metadataList>
+    </document>
+    <document name='owlcreek'>
+      <metadataList>
+	<metadata name='Title'>An Occurrence At Owl Creek Bridge</metadata>
+	<metadata name="Author">Ambrose Bierce</metadata>
+      </metadataList>
+    </document>
+    <document name='fishpatrol'>
+      <metadataList>
+	<metadata name='Title'>Tales of the Fish Patrol</metadata>
+	<metadata name="Author">Jack London</metadata>
+      </metadataList>
+    </document>
+  </documentList>
+</collectionConfig>
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/etc/collectionInit.xml
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/etc/collectionInit.xml	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/etc/collectionInit.xml	(revision 14125)
@@ -0,0 +1,2 @@
+<collectionInit class="XMLCollection"/>
+
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/import/bookfrag.dtd
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/import/bookfrag.dtd	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/import/bookfrag.dtd	(revision 14125)
@@ -0,0 +1,529 @@
+<!--This is bookfrag DTD-->
+
+<!--entity declarations-->
+<!--#############################################-->
+
+<!ENTITY % stdatts 
+"ref   IDREF  #IMPLIED
+ id    ID     #IMPLIED
+ type  CDATA  #IMPLIED
+ role  CDATA  #IMPLIED
+ class CDATA  #IMPLIED"
+>
+
+<!ENTITY % inline.class "|quote|emph|ital|reference|date|place|name|graphic|txterr|mkuperr|misc ">
+
+<!ENTITY % block.class "|letter|blockquote|footnote|note|list|deflist|table|blockgraphic">
+
+
+<!-- the top level element-->
+<!--##############################################-->
+
+<!ELEMENT book (acknowledge?,meta*,frontmatter?,bookbody,backmatter?,endmeta*)>
+
+<!--begin top level element declarations-->
+<!--##############################################-->
+
+
+<!--the acknowledge element is for a simple statement 
+designed to be placed at the beginning of the visible document.
+Suggested content:
+  Name of Book
+  Author
+  PG and HWG blurb
+  Original Transcriber + date
+  Marker 
+  e.g.
+  "Origin of the Species by Charles Darwin
+  A project of Project Gutenberg and the HTML Writers Guild.
+  Transcribed by  
+  Markup by Frank Boumphrey. Jan 22 2000"
+  -->
+
+<!ELEMENT acknowledge (#PCDATA %inline.class;)*>
+<!ATTLIST acknowledge
+  %stdatts;
+>
+
+<!--the meta tags are here to provide a means for comment 
+at either the very beginning or end of the document-->
+<!ELEMENT meta EMPTY>
+<!ATTLIST meta
+   content  CDATA  #REQUIRED
+   id       ID     #IMPLIED
+>
+
+<!ELEMENT endmeta EMPTY >
+<!ATTLIST endmeta
+   content  CDATA  #REQUIRED
+   id       ID     #IMPLIED
+>
+
+
+
+<!--the bookbody element contains the body of the book it can 
+consist of either part or chapter divisions-->
+
+<!ELEMENT bookbody (part*|chapter*)>
+
+<!--
+the backmatter element contains the backmatter of the book -->
+
+<!ELEMENT backmatter ((appendix|index|glossary|biblio|note)*,colophon?)>
+
+<!--The endmeta tag is groupedwith its twin meta-->
+
+
+<!--end top level element declarations-->
+
+<!--begin frontmatter element declarations-->
+<!--##############################################-->
+
+<!ELEMENT frontmatter (htitlepage|copypage|epigraph|titlepage|
+                toc|acksect|dedication|preface|introduction|miscfm)*>
+
+<!ELEMENT htitlepage (#PCDATA|title|subtitle|author|para|poem|song %inline.class;)*>
+<!ATTLIST htitlepage
+  %stdatts;
+>
+
+<!ELEMENT copypage (#PCDATA|para|poem|song|note %inline.class;)*>
+<!ATTLIST copypage
+  %stdatts;
+>
+
+<!ELEMENT epigraph (#PCDATA|para|poem|song|note|blockquote %inline.class;)*>
+<!ATTLIST epigraph
+  %stdatts;
+>
+
+
+<!ELEMENT titlepage (#PCDATA|partnum|title|subtitle|author|pubinfo|para|poem|song|note|line %inline.class;)*>
+<!ATTLIST titlepage
+  %stdatts;
+>
+
+<!ELEMENT pubinfo (#PCDATA|para|line %inline.class;)*>
+<!ATTLIST pubinfo
+  %stdatts;
+>
+
+
+<!ELEMENT toc (#PCDATA|title|subtitle|subsubtitle|item|list|deflist %inline.class;)*>
+<!--use type or role to describe toctype="other"-->
+<!ATTLIST toc
+  toctype (contents|maps|graphics|tables|other) "contents" 
+  %stdatts;
+>
+
+<!ELEMENT acksect (#PCDATA|para|poem|song|note %inline.class;)*>
+<!ATTLIST acksect
+  %stdatts;
+>
+
+<!ELEMENT dedication (#PCDATA|title|para|poem|song|note %inline.class;)*>
+<!ATTLIST dedication
+  %stdatts;
+>
+
+
+<!ELEMENT preface ((title|chapheader)?,(para|poem|song|sect1|simplesect %block.class;)*,endchap?,preauthor?)>
+<!ATTLIST preface  %stdatts;
+>
+
+<!ELEMENT introduction ((title|chapheader)?,(para|poem|song|sect1|simplesect %block.class;)*,endchap?)>
+<!ATTLIST introduction  %stdatts;
+>
+
+<!ELEMENT miscfm (#PCDATA|para|poem|song|note %inline.class;)*>
+<!ATTLIST miscfm
+  %stdatts;
+>
+
+<!ELEMENT preauthor (#PCDATA|author %inline.class;)*>
+<!ATTLIST preauthor
+  %stdatts;
+>
+
+
+
+<!--end frontmatter element declarations-->
+
+<!--begin bookbody element declarations-->
+<!--##############################################-->
+
+
+<!ELEMENT part (acknowledge?,(titlepage|toc|htitlepage)*,chapter*)>
+<!ATTLIST part
+  %stdatts;
+>
+
+<!ELEMENT chapter ((title|chapheader)?,(para|poem|song|sect1|simplesect|page %block.class;)*,endchap?)>
+<!ATTLIST chapter  %stdatts;
+>
+
+<!--end bookbody element declarations-->
+
+<!--the lowerlevel bookbody elements-->
+<!--##############################################-->
+
+<!--the chapter heading elements-->
+<!--##############################################-->
+
+
+
+
+<!ELEMENT title (#PCDATA %inline.class;)*>
+<!ATTLIST title
+  %stdatts;
+>
+
+<!ELEMENT subtitle (#PCDATA %inline.class;)*>
+<!ATTLIST subtitle
+  %stdatts;
+>
+
+<!ELEMENT subsubtitle (#PCDATA %inline.class;)*>
+<!ATTLIST subsubtitle
+  %stdatts;
+>
+
+
+
+<!--validity constraint. Only one title,chapnum and chapsummary -->
+<!ELEMENT chapheader (title|subtitle|chapnum|chapsummary|blockquote|para|note)*>
+<!ATTLIST chapheader
+  %stdatts;
+>
+
+
+<!ELEMENT chapnum (#PCDATA %inline.class;)*>
+<!ATTLIST chapnum
+  %stdatts;
+>
+
+<!ELEMENT chapsummary (#PCDATA %inline.class;)*>
+<!ATTLIST chapsummary
+  %stdatts;
+>
+
+
+<!--begin backmatter element declarations-->
+<!--##############################################-->
+
+<!--end backmatter element declarations-->
+
+<!ELEMENT index (title|item|list|deflist|note)*>
+<!ATTLIST index
+  indtype (contents|authors|firstlines|tables|other) "contents" 
+  %stdatts;
+>
+
+<!ELEMENT glossary (title|item|list|deflist|note)*>
+<!ATTLIST glossary  
+  %stdatts;
+>
+
+<!ELEMENT biblio (title|item|list|deflist|note)*>
+<!ATTLIST biblio  
+  %stdatts;
+>
+
+
+<!ELEMENT appendix ((title|chapheader)?,(para|poem|song|sect1|simplesect %block.class;)*,endchap?)>
+<!ATTLIST appendix  %stdatts;
+>
+
+<!ELEMENT colophon (#PCDATA|para|poem|song %inline.class;)*>
+<!ATTLIST colophon
+  %stdatts;
+>
+
+<!--the block elements-->
+<!--##############################################-->
+
+
+<!--validity constraint. Only one title per paragraph-->
+<!ELEMENT para (#PCDATA|title %inline.class;)*>
+<!ATTLIST para
+  %stdatts;
+>
+
+<!ELEMENT simplesect (title,(subtitle|para|poem|song %block.class;)*)>
+<!ATTLIST simplesect
+  %stdatts;
+>
+
+<!ELEMENT sect1 (title,(sect2|simplesect|para|poem|song %block.class;)*)>
+<!ATTLIST sect1
+  %stdatts;
+>
+
+<!ELEMENT sect2 (title,(sect3|simplesect|subtitle|para|poem|song  %block.class;)*)>
+<!ATTLIST sect2
+  %stdatts;
+>
+
+<!ELEMENT sect3 (title,(sect4|simplesect|subtitle|para|poem|song  %block.class;)*)>
+<!ATTLIST sect3
+  %stdatts;
+>
+
+<!ELEMENT sect4 (title,(simplesect|subtitle|para|poem|song  %block.class;)*)>
+<!ATTLIST sect4
+  %stdatts;
+>
+
+<!ELEMENT page (#PCDATA %inline.class;)*>
+<!ATTLIST page
+  %stdatts;
+>
+
+<!ELEMENT misc (#PCDATA %inline.class;)*>
+<!ATTLIST misc
+  %stdatts;
+>
+
+
+
+<!ELEMENT blockquote (title?,(para|poem|song)*,attrib?)>
+<!ATTLIST blockquote
+  %stdatts;
+>
+
+<!ELEMENT attrib (#PCDATA %inline.class;)*>
+<!ATTLIST attrib
+  %stdatts;
+>
+
+<!ELEMENT caption (#PCDATA %inline.class;)*>
+<!ATTLIST caption
+  %stdatts;
+>
+<!--##############################################-->
+<!--poetry and songs in the text-->
+<!ELEMENT poem (#PCDATA|title|subtitle|verse|line|note|footnote %inline.class;)*>
+<!ATTLIST poem
+  %stdatts;
+>
+
+<!ELEMENT song (#PCDATA|title|subtitle|verse|line|note|footnote %inline.class;)*>
+<!ATTLIST song
+  %stdatts;
+>
+
+
+<!ELEMENT verse (title|subtitle|line|note)*>
+<!ATTLIST verse
+  %stdatts;
+>
+
+<!ELEMENT line (#PCDATA %inline.class;)*>
+<!ATTLIST line
+  %stdatts;
+>
+
+
+<!--validity constraint: Only one title per poem or per verse-->
+
+<!--end of poetry in the text-->
+
+<!--letter module-->
+
+<!ELEMENT letter (address|to|from|salut|sig|title|subtitle|para|poem|song|line|note)*>
+<!ATTLIST letter
+  %stdatts;
+>
+
+<!ELEMENT address (#PCDATA|para|line %inline.class;)*>
+<!ATTLIST address
+  %stdatts;
+>
+
+<!ELEMENT to (#PCDATA|para|line %inline.class;)*>
+<!ATTLIST to
+  %stdatts;
+>
+
+
+<!ELEMENT from (#PCDATA|para|line %inline.class;)*>
+<!ATTLIST from
+  %stdatts;
+>
+
+
+<!ELEMENT salut (#PCDATA|para|line %inline.class;)*>
+<!ATTLIST salut
+  %stdatts;
+>
+
+
+<!ELEMENT sig (#PCDATA|para|line %inline.class;)*>
+<!ATTLIST sig
+  %stdatts;
+>
+
+
+<!--end letters module-->
+<!--endchap-->
+<!--##############################################-->
+<!--
+  Endchap should only be used when there is a 
+  considerable ammount of material to be organized.
+  For the occasional note footnote and note will suffice
+-->
+
+<!ELEMENT endchap (para %block.class;)*>
+<!ATTLIST endchap  %stdatts;
+>
+
+<!--lists-->
+<!--##############################################-->
+
+
+<!ELEMENT list (title?,(list|item)*)>
+<!ATTLIST list
+  %stdatts;
+>
+
+<!ELEMENT item (#PCDATA|para|poem|song|simplesect %block.class; %inline.class;)*>
+<!ATTLIST item
+  %stdatts;
+>
+
+<!ELEMENT deflist (title?,(item,desc?,def*)*)>
+<!ATTLIST deflist
+  %stdatts;
+>
+
+<!ELEMENT desc (#PCDATA %inline.class;)*>
+<!ATTLIST desc
+  %stdatts;
+>
+
+<!ELEMENT def (#PCDATA %inline.class;)*>
+<!ATTLIST def
+  %stdatts;
+>
+<!--end lists-->
+<!--table element-->
+<!--##############################################-->
+
+
+<!ELEMENT table (title?,row*,caption?)>
+<!ATTLIST table
+  %stdatts;
+>
+
+<!ELEMENT row (cell)*>
+<!ATTLIST row
+  %stdatts;
+>
+
+<!ELEMENT cell (#PCDATA %block.class; %inline.class;)*>
+<!ATTLIST cell
+  %stdatts;
+>
+
+<!--end table-->
+
+<!--graphics-->
+<!--##############################################-->
+
+<!--
+  Note that the required desc attribute is added 
+  text composed by the marker.
+-->
+
+<!ELEMENT graphic EMPTY >
+<!ATTLIST graphic
+  desc CDATA #REQUIRED
+  href CDATA #REQUIRED
+  %stdatts;
+>
+
+<!ELEMENT blockgraphic (title?,graphic,caption?)>
+<!ATTLIST blockgraphic
+  %stdatts;
+>
+
+
+<!--the inline elements-->
+<!--##############################################-->
+
+
+
+<!ELEMENT footnote (#PCDATA %inline.class;)*>
+<!ATTLIST footnote
+  %stdatts;
+>
+
+<!ELEMENT note (#PCDATA %inline.class;)*>
+<!ATTLIST note
+  %stdatts;
+>
+
+
+<!ELEMENT quote (#PCDATA %inline.class;)*>
+<!ATTLIST quote
+  %stdatts;
+>
+
+<!ELEMENT emph (#PCDATA %inline.class;)*>
+<!ATTLIST emph
+  %stdatts;
+>
+
+<!ELEMENT ital (#PCDATA %inline.class;)*>
+<!ATTLIST ital
+  %stdatts;
+>
+
+<!ELEMENT reference (#PCDATA %inline.class;)*>
+<!ATTLIST reference
+  %stdatts;
+>
+
+<!ELEMENT author (#PCDATA %inline.class;)*>
+<!ATTLIST author
+  %stdatts;
+>
+
+<!ELEMENT date (#PCDATA %inline.class;)*>
+<!ATTLIST date
+  %stdatts;
+>
+
+<!ELEMENT place (#PCDATA %inline.class;)*>
+<!ATTLIST place
+  %stdatts;
+>
+
+<!ELEMENT name (#PCDATA %inline.class;)*>
+<!ATTLIST name
+  %stdatts;
+>
+
+
+<!--use to enclose the text you think is in error
+optional explanation if error is not obvious-->
+<!ELEMENT txterr (#PCDATA)*>
+<!ATTLIST txterr
+  explain  CDATA  #IMPLIED
+  %stdatts;
+>
+
+<!--an explanation is required-->
+<!ELEMENT mkuperr EMPTY>
+<!ATTLIST mkuperr
+  explain  CDATA  #REQUIRED
+  %stdatts;
+>
+
+<!--added as titlepage content  Feb/6/00-->
+<!ELEMENT partnum (#PCDATA %inline.class;)*>
+<!ATTLIST partnum
+  %stdatts;
+>
+
+<!--End of bookfrag dtd-->
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/import/fishpatrol.xml
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/import/fishpatrol.xml	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/import/fishpatrol.xml	(revision 14125)
@@ -0,0 +1,5033 @@
+<?xml version="1.0"?>
+<!DOCTYPE gutbook SYSTEM "gutbook1.dtd">
+
+<?xml-stylesheet type="text/css" href="darwin.css"?>
+
+
+<gutbook>
+<gutblurb>
+<para>
+Project Gutenberg's Etext of Tales of the Fish Patrol, by London
+#8 in our series by Jack London
+</para>
+
+<para>
+
+Copyright laws are changing all over the world, be sure to check
+the copyright laws for your country before posting these files!!
+</para>
+
+<para>
+Please take a look at the important information in this header.
+We encourage you to keep this file on your own disk, keeping an
+electronic path open for the next readers.  Do not remove this.
+</para>
+
+<para>
+
+**Welcome To The World of Free Plain Vanilla Electronic Texts**
+</para>
+
+<para>
+**Etexts Readable By Both Humans and By Computers, Since 1971**
+</para>
+
+<para>
+*These Etexts Prepared By Hundreds of Volunteers and Donations*
+</para>
+
+<para>
+Information on contacting Project Gutenberg to get Etexts, and
+further information is included below.  We need your donations.
+</para>
+
+<para>
+
+Tales of the Fish Patrol
+</para>
+
+<para>
+by Jack London
+</para>
+
+<para>
+May, 1997  [Etext #911]
+</para>
+
+<para>
+
+Project Gutenberg's Etext of Tales of the Fish Patrol, by London
+*****This file should be named totfp10.txt or totfp10.zip******
+</para>
+
+<para>
+Corrected EDITIONS of our etexts get a new NUMBER, totfp11.txt.
+VERSIONS based on separate sources get new LETTER, totfp10a.txt.
+</para>
+
+<para>
+
+Scanned and proofed by David Price
+ccx074@coventry.ac.uk
+</para>
+
+<para>
+
+We are now trying to release all our books one month in advance
+of the official release dates, for time for better editing.
+</para>
+
+<para>
+Please note:  neither this list nor its contents are final till
+midnight of the last day of the month of any such announcement.
+The official release date of all Project Gutenberg Etexts is at
+Midnight, Central Time, of the last day of the stated month.  A
+preliminary version may often be posted for suggestion, comment
+and editing by those who wish to do so.  To be sure you have an
+up to date first edition [xxxxx10x.xxx] please check file sizes
+in the first week of the next month.  Since our ftp program has
+a bug in it that scrambles the date [tried to fix and failed] a
+look at the file size will have to do, but we will try to see a
+new copy has at least one byte more or less.
+</para>
+
+<para>
+
+Information about Project Gutenberg (one page)
+</para>
+
+<para>
+We produce about two million dollars for each hour we work.  The
+fifty hours is one conservative estimate for how long it we take
+to get any etext selected, entered, proofread, edited, copyright
+searched and analyzed, the copyright letters written, etc.  This
+projected audience is one hundred million readers.  If our value
+per text is nominally estimated at one dollar then we produce $2
+million dollars per hour this year as we release thirty-two text
+files per month:  or 400 more Etexts in 1996 for a total of 800.
+If these reach just 10% of the computerized population, then the
+total should reach 80 billion Etexts.
+</para>
+
+<para>
+The Goal of Project Gutenberg is to Give Away One Trillion Etext
+Files by the December 31, 2001.  [10,000 x 100,000,000=Trillion]
+This is ten thousand titles each to one hundred million readers,
+which is only 10% of the present number of computer users.  2001
+should have at least twice as many computer users as that, so it
+will require us reaching less than 5% of the users in 2001.
+</para>
+
+<para>
+
+We need your donations more than ever!
+</para>
+
+<para>
+
+All donations should be made to "Project Gutenberg/CMU": and are
+tax deductible to the extent allowable by law.  (CMU = Carnegie-
+Mellon University).
+</para>
+
+<para>
+For these and other matters, please mail to:
+</para>
+
+<para>
+Project Gutenberg
+P. O. Box  2782
+Champaign, IL 61825
+</para>
+
+<para>
+When all other email fails try our Executive Director:
+Michael S. Hart &lt;hart@pobox.com&gt;
+</para>
+
+<para>
+We would prefer to send you this information by email
+(Internet, Bitnet, Compuserve, ATTMAIL or MCImail).
+</para>
+
+<para>
+******
+If you have an FTP program (or emulator), please
+FTP directly to the Project Gutenberg archives:
+[Mac users, do NOT point and click. . .type]
+</para>
+
+<para>
+ftp uiarchive.cso.uiuc.edu
+login:  anonymous
+password:  your@login
+cd etext/etext90 through /etext96
+or cd etext/articles [get suggest gut for more information]
+dir [to see files]
+get or mget [to get files. . .set bin for zip files]
+GET INDEX?00.GUT
+for a list of books
+and
+GET NEW GUT for general information
+and
+MGET GUT* for newsletters.
+</para>
+
+<para>
+**Information prepared by the Project Gutenberg legal advisor**
+(Three Pages)
+</para>
+
+<para>
+
+***START**THE SMALL PRINT!**FOR PUBLIC DOMAIN ETEXTS**START***
+Why is this "Small Print!" statement here?  You know: lawyers.
+They tell us you might sue us if there is something wrong with
+your copy of this etext, even if you got it for free from
+someone other than us, and even if what's wrong is not our
+fault.  So, among other things, this "Small Print!" statement
+disclaims most of our liability to you.  It also tells you how
+you can distribute copies of this etext if you want to.
+</para>
+
+<para>
+*BEFORE!* YOU USE OR READ THIS ETEXT
+By using or reading any part of this PROJECT GUTENBERG-tm
+etext, you indicate that you understand, agree to and accept
+this "Small Print!" statement.  If you do not, you can receive
+a refund of the money (if any) you paid for this etext by
+sending a request within 30 days of receiving it to the person
+you got it from.  If you received this etext on a physical
+medium (such as a disk), you must return it with your request.
+</para>
+
+<para>
+ABOUT PROJECT GUTENBERG-TM ETEXTS
+This PROJECT GUTENBERG-tm etext, like most PROJECT GUTENBERG-
+tm etexts, is a "public domain" work distributed by Professor
+Michael S. Hart through the Project Gutenberg Association at
+Carnegie-Mellon University (the "Project").  Among other
+things, this means that no one owns a United States copyright
+on or for this work, so the Project (and you!) can copy and
+distribute it in the United States without permission and
+without paying copyright royalties.  Special rules, set forth
+below, apply if you wish to copy and distribute this etext
+under the Project's "PROJECT GUTENBERG" trademark.
+</para>
+
+<para>
+To create these etexts, the Project expends considerable
+efforts to identify, transcribe and proofread public domain
+works.  Despite these efforts, the Project's etexts and any
+medium they may be on may contain "Defects".  Among other
+things, Defects may take the form of incomplete, inaccurate or
+corrupt data, transcription errors, a copyright or other
+intellectual property infringement, a defective or damaged
+disk or other etext medium, a computer virus, or computer
+codes that damage or cannot be read by your equipment.
+</para>
+
+<para>
+LIMITED WARRANTY; DISCLAIMER OF DAMAGES
+But for the "Right of Replacement or Refund" described below,
+[1] the Project (and any other party you may receive this
+etext from as a PROJECT GUTENBERG-tm etext) disclaims all
+liability to you for damages, costs and expenses, including
+legal fees, and [2] YOU HAVE NO REMEDIES FOR NEGLIGENCE OR
+UNDER STRICT LIABILITY, OR FOR BREACH OF WARRANTY OR CONTRACT,
+INCLUDING BUT NOT LIMITED TO INDIRECT, CONSEQUENTIAL, PUNITIVE
+OR INCIDENTAL DAMAGES, EVEN IF YOU GIVE NOTICE OF THE
+POSSIBILITY OF SUCH DAMAGES.
+</para>
+
+<para>
+If you discover a Defect in this etext within 90 days of
+receiving it, you can receive a refund of the money (if any)
+you paid for it by sending an explanatory note within that
+time to the person you received it from.  If you received it
+on a physical medium, you must return it with your note, and
+such person may choose to alternatively give you a replacement
+copy.  If you received it electronically, such person may
+choose to alternatively give you a second opportunity to
+receive it electronically.
+</para>
+
+<para>
+THIS ETEXT IS OTHERWISE PROVIDED TO YOU "AS-IS".  NO OTHER
+WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, ARE MADE TO YOU AS
+TO THE ETEXT OR ANY MEDIUM IT MAY BE ON, INCLUDING BUT NOT
+LIMITED TO WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
+PARTICULAR PURPOSE.
+</para>
+
+<para>
+Some states do not allow disclaimers of implied warranties or
+the exclusion or limitation of consequential damages, so the
+above disclaimers and exclusions may not apply to you, and you
+may have other legal rights.
+</para>
+
+<para>
+INDEMNITY
+You will indemnify and hold the Project, its directors,
+officers, members and agents harmless from all liability, cost
+and expense, including legal fees, that arise directly or
+indirectly from any of the following that you do or cause:
+[1] distribution of this etext, [2] alteration, modification,
+or addition to the etext, or [3] any Defect.
+</para>
+
+<para>
+DISTRIBUTION UNDER "PROJECT GUTENBERG-tm"
+You may distribute copies of this etext electronically, or by
+disk, book or any other medium if you either delete this
+"Small Print!" and all other references to Project Gutenberg,
+or:
+</para>
+
+<para>
+[1]  Only give exact copies of it.  Among other things, this
+     requires that you do not remove, alter or modify the
+     etext or this "small print!" statement.  You may however,
+     if you wish, distribute this etext in machine readable
+     binary, compressed, mark-up, or proprietary form,
+     including any form resulting from conversion by word pro-
+     cessing or hypertext software, but only so long as
+     *EITHER*:
+</para>
+
+<para>
+     [*]  The etext, when displayed, is clearly readable, and
+          does *not* contain characters other than those
+          intended by the author of the work, although tilde
+          (~), asterisk (*) and underline (_) characters may
+          be used to convey punctuation intended by the
+          author, and additional characters may be used to
+          indicate hypertext links; OR
+</para>
+
+<para>
+     [*]  The etext may be readily converted by the reader at
+          no expense into plain ASCII, EBCDIC or equivalent
+          form by the program that displays the etext (as is
+          the case, for instance, with most word processors);
+          OR
+</para>
+
+<para>
+     [*]  You provide, or agree to also provide on request at
+          no additional cost, fee or expense, a copy of the
+          etext in its original plain ASCII form (or in EBCDIC
+          or other equivalent proprietary form).
+</para>
+
+<para>
+[2]  Honor the etext refund and replacement provisions of this
+     "Small Print!" statement.
+</para>
+
+<para>
+[3]  Pay a trademark license fee to the Project of 20% of the
+     net profits you derive calculated using the method you
+     already use to calculate your applicable taxes.  If you
+     don't derive profits, no royalty is due.  Royalties are
+     payable to "Project Gutenberg Association/Carnegie-Mellon
+     University" within the 60 days following each
+     date you prepare (or were legally required to prepare)
+     your annual (or equivalent periodic) tax return.
+</para>
+
+<para>
+WHAT IF YOU *WANT* TO SEND MONEY EVEN IF YOU DON'T HAVE TO?
+The Project gratefully accepts contributions in money, time,
+scanning machines, OCR software, public domain etexts, royalty
+free copyright licenses, and every other sort of contribution
+you can think of.  Money should be paid to "Project Gutenberg
+Association / Carnegie-Mellon University".
+</para>
+
+<para>
+*END*THE SMALL PRINT! FOR PUBLIC DOMAIN ETEXTS*Ver.04.29.93*END*
+</para>
+
+
+
+<para>
+Tales of the Fish Patrol by Jack London
+Scanned and proofed by David Price
+ccx074@coventry.ac.uk
+</para>
+</gutblurb>
+
+<markupblurb>
+Original markup by Frank Boumphrey.  2/4/2000
+Validated against gutbook1.dtd using MSXML parser
+</markupblurb>
+
+
+<book>
+<acknowledge>A production of Project Gutenberg and the HTML Writers Guild. E-text by David Price. Markup by Frank Boumphrey</acknowledge>
+<frontmatter>
+<titlepage>
+<title>
+Tales of the Fish Patrol
+</title>
+<author>Jack London</author>
+</titlepage>
+</frontmatter>
+
+<bookbody>
+<chapter>
+<title>
+WHITE AND YELLOW</title>
+
+
+<para>
+San Francisco Bay is so large that often its storms are more
+disastrous to ocean-going craft than is the ocean itself in its
+violent moments.  The waters of the bay contain all manner of fish,
+wherefore its surface is ploughed by the keels of all manner of
+fishing boats manned by all manner of fishermen.  To protect the
+fish from this motley floating population many wise laws have been
+passed, and there is a fish patrol to see that these laws are
+enforced.  Exciting times are the lot of the fish patrol:  in its
+history more than one dead patrolman has marked defeat, and more
+often dead fishermen across their illegal nets have marked success.
+</para>
+
+<para>
+Wildest among the fisher-folk may be accounted the Chinese shrimp-
+catchers.  It is the habit of the shrimp to crawl along the bottom
+in vast armies till it reaches fresh water, when it turns about and
+crawls back again to the salt.  And where the tide ebbs and flows,
+the Chinese sink great bag-nets to the bottom, with gaping mouths,
+into which the shrimp crawls and from which it is transferred to
+the boiling-pot.  This in itself would not be bad, were it not for
+the small mesh of the nets, so small that the tiniest fishes,
+little new-hatched things not a quarter of an inch long, cannot
+pass through.  The beautiful beaches of Points Pedro and Pablo,
+where are the shrimp-catchers' villages, are made fearful by the
+stench from myriads of decaying fish, and against this wasteful
+destruction it has ever been the duty of the fish patrol to act.
+</para>
+
+<para>
+When I was a youngster of sixteen, a good sloop-sailor and all-
+round bay-waterman, my sloop, the Reindeer, was chartered by the
+Fish Commission, and I became for the time being a deputy
+patrolman.  After a deal of work among the Greek fishermen of the
+Upper Bay and rivers, where knives flashed at the beginning of
+trouble and men permitted themselves to be made prisoners only
+after a revolver was thrust in their faces, we hailed with delight
+an expedition to the Lower Bay against the Chinese shrimp-catchers.
+</para>
+
+<para>
+There were six of us, in two boats, and to avoid suspicion we ran
+down after dark and dropped anchor under a projecting bluff of land
+known as Point Pinole.  As the east paled with the first light of
+dawn we got under way again, and hauled close on the land breeze as
+we slanted across the bay toward Point Pedro.  The morning mists
+curled and clung to the water so that we could see nothing, but we
+busied ourselves driving the chill from our bodies with hot coffee.
+Also we had to devote ourselves to the miserable task of bailing,
+for in some incomprehensible way the Reindeer had sprung a generous
+leak.  Half the night had been spent in overhauling the ballast and
+exploring the seams, but the labor had been without avail.  The
+water still poured in, and perforce we doubled up in the cockpit
+and tossed it out again.
+</para>
+
+<para>
+After coffee, three of the men withdrew to the other boat, a
+Columbia River salmon boat, leaving three of us in the Reindeer.
+Then the two craft proceeded in company till the sun showed over
+the eastern sky-line.  Its fiery rays dispelled the clinging
+vapors, and there, before our eyes, like a picture, lay the shrimp
+fleet, spread out in a great half-moon, the tips of the crescent
+fully three miles apart, and each junk moored fast to the buoy of a
+shrimp-net.  But there was no stir, no sign of life.
+</para>
+
+<para>
+The situation dawned upon us.  While waiting for slack water, in
+which to lift their heavy nets from the bed of the bay, the Chinese
+had all gone to sleep below.  We were elated, and our plan of
+battle was swiftly formed.
+</para>
+
+<para>
+"Throw each of your two men on to a junk," whispered Le Grant to me
+from the salmon boat.  "And you make fast to a third yourself.
+We'll do the same, and there's no reason in the world why we
+shouldn't capture six junks at the least."
+</para>
+
+<para>
+Then we separated.  I put the Reindeer about on the other tack, ran
+up under the lee of a junk, shivered the mainsail into the wind and
+lost headway, and forged past the stern of the junk so slowly and
+so near that one of the patrolmen stepped lightly aboard.  Then I
+kept off, filled the mainsail, and bore away for a second junk.
+</para>
+
+<para>
+Up to this time there had been no noise, but from the first junk
+captured by the salmon boat an uproar now broke forth.  There was
+shrill Oriental yelling, a pistol shot, and more yelling.
+</para>
+
+<para>
+"It's all up.  They're warning the others," said George, the
+remaining patrolman, as he stood beside me in the cockpit.
+</para>
+
+<para>
+By this time we were in the thick of the fleet, and the alarm was
+spreading with incredible swiftness.  The decks were beginning to
+swarm with half-awakened and half-naked Chinese.  Cries and yells
+of warning and anger were flying over the quiet water, and
+somewhere a conch shell was being blown with great success.  To the
+right of us I saw the captain of a junk chop away his mooring line
+with an axe and spring to help his crew at the hoisting of the
+huge, outlandish lug-sail.  But to the left the first heads were
+popping up from below on another junk, and I rounded up the
+Reindeer alongside long enough for George to spring aboard.
+</para>
+
+<para>
+The whole fleet was now under way.  In addition to the sails they
+had gotten out long sweeps, and the bay was being ploughed in every
+direction by the fleeing junks.  I was now alone in the Reindeer,
+seeking feverishly to capture a third prize.  The first junk I took
+after was a clean miss, for it trimmed its sheets and shot away
+surprisingly into the wind.  By fully half a point it outpointed
+the Reindeer, and I began to feel respect for the clumsy craft.
+Realizing the hopelessness of the pursuit, I filled away, threw out
+the main-sheet, and drove down before the wind upon the junks to
+leeward, where I had them at a disadvantage.
+</para>
+
+<para>
+The one I had selected wavered indecisively before me, and, as I
+swung wide to make the boarding gentle, filled suddenly and darted
+away, the smart Mongols shouting a wild rhythm as they bent to the
+sweeps.  But I had been ready for this.  I luffed suddenly.
+Putting the tiller hard down, and holding it down with my body, I
+brought the main-sheet in, hand over hand, on the run, so as to
+retain all possible striking force.  The two starboard sweeps of
+the junk were crumpled up, and then the two boats came together
+with a crash.  The Reindeer's bowsprit, like a monstrous hand,
+reached over and ripped out the junk's chunky mast and towering
+sail.
+</para>
+
+<para>
+This was met by a curdling yell of rage.  A big Chinaman,
+remarkably evil-looking, with his head swathed in a yellow silk
+handkerchief and face badly pock-marked, planted a pike-pole on the
+Reindeer's bow and began to shove the entangled boats apart.
+Pausing long enough to let go the jib halyards, and just as the
+Reindeer cleared and began to drift astern, I leaped aboard the
+junk with a line and made fast.  He of the yellow handkerchief and
+pock-marked face came toward me threateningly, but I put my hand
+into my hip pocket, and he hesitated.  I was unarmed, but the
+Chinese have learned to be fastidiously careful of American hip
+pockets, and it was upon this that I depended to keep him and his
+savage crew at a distance.
+</para>
+
+<para>
+I ordered him to drop the anchor at the junk's bow, to which he
+replied, "No sabbe."  The crew responded in like fashion, and
+though I made my meaning plain by signs, they refused to
+understand.  Realizing the inexpediency of discussing the matter, I
+went forward myself, overran the line, and let the anchor go.
+</para>
+
+<para>
+"Now get aboard, four of you," I said in a loud voice, indicating
+with my fingers that four of them were to go with me and the fifth
+was to remain by the junk.  The Yellow Handkerchief hesitated; but
+I repeated the order fiercely (much more fiercely than I felt), at
+the same time sending my hand to my hip.  Again the Yellow
+Handkerchief was overawed, and with surly looks he led three of his
+men aboard the Reindeer.  I cast off at once, and, leaving the jib
+down, steered a course for George's junk.  Here it was easier, for
+there were two of us, and George had a pistol to fall back on if it
+came to the worst.  And here, as with my junk, four Chinese were
+transferred to the sloop and one left behind to take care of
+things.
+</para>
+
+<para>
+Four more were added to our passenger list from the third junk.  By
+this time the salmon boat had collected its twelve prisoners and
+came alongside, badly overloaded.  To make matters worse, as it was
+a small boat, the patrolmen were so jammed in with their prisoners
+that they would have little chance in case of trouble.
+</para>
+
+<para>
+"You'll have to help us out," said Le Grant.
+</para>
+
+<para>
+I looked over my prisoners, who had crowded into the cabin and on
+top of it.  "I can take three," I answered.
+</para>
+
+<para>
+"Make it four," he suggested, "and I'll take Bill with me."  (Bill
+was the third patrolman.)  "We haven't elbow room here, and in case
+of a scuffle one white to every two of them will be just about the
+right proportion."
+</para>
+
+<para>
+The exchange was made, and the salmon boat got up its spritsail and
+headed down the bay toward the marshes off San Rafael.  I ran up
+the jib and followed with the Reindeer.  San Rafael, where we were
+to turn our catch over to the authorities, communicated with the
+bay by way of a long and tortuous slough, or marshland creek, which
+could be navigated only when the tide was in.  Slack water had
+come, and, as the ebb was commencing, there was need for hurry if
+we cared to escape waiting half a day for the next tide.
+</para>
+
+<para>
+But the land breeze had begun to die away with the rising sun, and
+now came only in failing puffs.  The salmon boat got out its oars
+and soon left us far astern.  Some of the Chinese stood in the
+forward part of the cockpit, near the cabin doors, and once, as I
+leaned over the cockpit rail to flatten down the jib-sheet a bit, I
+felt some one brush against my hip pocket.  I made no sign, but out
+of the corner of my eye I saw that the Yellow Handkerchief had
+discovered the emptiness of the pocket which had hitherto overawed
+him.
+</para>
+
+<para>
+To make matters serious, during all the excitement of boarding the
+junks the Reindeer had not been bailed, and the water was beginning
+to slush over the cockpit floor.  The shrimp-catchers pointed at it
+and looked to me questioningly.
+</para>
+
+<para>
+"Yes," I said.  "Bime by, allee same dlown, velly quick, you no
+bail now.  Sabbe?"
+</para>
+
+<para>
+No, they did not "sabbe," or at least they shook their heads to
+that effect, though they chattered most comprehendingly to one
+another in their own lingo.  I pulled up three or four of the
+bottom boards, got a couple of buckets from a locker, and by
+unmistakable sign-language invited them to fall to.  But they
+laughed, and some crowded into the cabin and some climbed up on
+top.
+</para>
+
+<para>
+Their laughter was not good laughter.  There was a hint of menace
+in it, a maliciousness which their black looks verified.  The
+Yellow Handkerchief, since his discovery of my empty pocket, had
+become most insolent in his bearing, and he wormed about among the
+other prisoners, talking to them with great earnestness.
+</para>
+
+<para>
+Swallowing my chagrin, I stepped down into the cockpit and began
+throwing out the water.  But hardly had I begun, when the boom
+swung overhead, the mainsail filled with a jerk, and the Reindeer
+heeled over.  The day wind was springing up.  George was the
+veriest of landlubbers, so I was forced to give over bailing and
+take the tiller.  The wind was blowing directly off Point Pedro and
+the high mountains behind, and because of this was squally and
+uncertain, half the time bellying the canvas out and the other half
+flapping it idly.
+</para>
+
+<para>
+George was about the most all-round helpless man I had ever met.
+Among his other disabilities, he was a consumptive, and I knew that
+if he attempted to bail, it might bring on a hemorrhage.  Yet the
+rising water warned me that something must be done.  Again I
+ordered the shrimp-catchers to lend a hand with the buckets.  They
+laughed defiantly, and those inside the cabin, the water up to
+their ankles, shouted back and forth with those on top.
+</para>
+
+<para>
+"You'd better get out your gun and make them bail," I said to
+George.
+</para>
+
+<para>
+But he shook his head and showed all too plainly that he was
+afraid.  The Chinese could see the funk he was in as well as I
+could, and their insolence became insufferable.  Those in the cabin
+broke into the food lockers, and those above scrambled down and
+joined them in a feast on our crackers and canned goods.
+</para>
+
+<para>
+"What do we care?" George said weakly.
+</para>
+
+<para>
+I was fuming with helpless anger.  "If they get out of hand, it
+will be too late to care.  The best thing you can do is to get them
+in check right now."
+</para>
+
+<para>
+The water was rising higher and higher, and the gusts, forerunners
+of a steady breeze, were growing stiffer and stiffer.  And between
+the gusts, the prisoners, having gotten away with a week's grub,
+took to crowding first to one side and then to the other till the
+Reindeer rocked like a cockle-shell.  Yellow Handkerchief
+approached me, and, pointing out his village on the Point Pedro
+beach, gave me to understand that if I turned the Reindeer in that
+direction and put them ashore, they, in turn, would go to bailing.
+By now the water in the cabin was up to the bunks, and the bed-
+clothes were sopping.  It was a foot deep on the cockpit floor.
+Nevertheless I refused, and I could see by George's face that he
+was disappointed.
+</para>
+
+<para>
+"If you don't show some nerve, they'll rush us and throw us
+overboard," I said to him.  "Better give me your revolver, if you
+want to be safe."
+</para>
+
+<para>
+"The safest thing to do," he chattered cravenly, "is to put them
+ashore.  I, for one, don't want to be drowned for the sake of a
+handful of dirty Chinamen."
+</para>
+
+<para>
+"And I, for another, don't care to give in to a handful of dirty
+Chinamen to escape drowning," I answered hotly.
+</para>
+
+<para>
+"You'll sink the Reindeer under us all at this rate," he whined.
+"And what good that'll do I can't see."
+</para>
+
+<para>
+"Every man to his taste," I retorted.
+</para>
+
+<para>
+He made no reply, but I could see he was trembling pitifully.
+Between the threatening Chinese and the rising water he was beside
+himself with fright; and, more than the Chinese and the water, I
+feared him and what his fright might impel him to do.  I could see
+him casting longing glances at the small skiff towing astern, so in
+the next calm I hauled the skiff alongside.  As I did so his eyes
+brightened with hope; but before he could guess my intention, I
+stove the frail bottom through with a hand-axe, and the skiff
+filled to its gunwales.
+</para>
+
+<para>
+"It's sink or float together," I said.  "And if you'll give me your
+revolver, I'll have the Reindeer bailed out in a jiffy."
+</para>
+
+<para>
+"They're too many for us," he whimpered.  "We can't fight them
+all."
+</para>
+
+<para>
+I turned my back on him in disgust.  The salmon boat had long since
+passed from sight behind a little archipelago known as the Marin
+Islands, so no help could be looked for from that quarter.  Yellow
+Handkerchief came up to me in a familiar manner, the water in the
+cockpit slushing against his legs.  I did not like his looks.  I
+felt that beneath the pleasant smile he was trying to put on his
+face there was an ill purpose.  I ordered him back, and so sharply
+that he obeyed.
+</para>
+
+<para>
+"Now keep your distance," I commanded, "and don't you come closer!"
+</para>
+
+<para>
+"Wha' fo'?" he demanded indignantly.  "I t'ink-um talkee talkee
+heap good."
+</para>
+
+<para>
+"Talkee talkee," I answered bitterly, for I knew now that he had
+understood all that passed between George and me.  "What for talkee
+talkee?  You no sabbe talkee talkee."
+</para>
+
+<para>
+He grinned in a sickly fashion.  "Yep, I sabbe velly much.  I
+honest Chinaman."
+</para>
+
+<para>
+"All right," I answered.  "You sabbe talkee talkee, then you bail
+water plenty plenty.  After that we talkee talkee."
+</para>
+
+<para>
+He shook his head, at the same time pointing over his shoulder to
+his comrades.  "No can do.  Velly bad Chinamen, heap velly bad.  I
+t'ink-um - "
+</para>
+
+<para>
+"Stand back!" I shouted, for I had noticed his hand disappear
+beneath his blouse and his body prepare for a spring.
+</para>
+
+<para>
+Disconcerted, he went back into the cabin, to hold a council,
+apparently, from the way the jabbering broke forth.  The Reindeer
+was very deep in the water, and her movements had grown quite
+loggy.  In a rough sea she would have inevitably swamped; but the
+wind, when it did blow, was off the land, and scarcely a ripple
+disturbed the surface of the bay.
+</para>
+
+<para>
+"I think you'd better head for the beach," George said abruptly, in
+a manner that told me his fear had forced him to make up his mind
+to some course of action.
+</para>
+
+<para>
+"I think not," I answered shortly.
+</para>
+
+<para>
+"I command you," he said in a bullying tone.
+</para>
+
+<para>
+"I was commanded to bring these prisoners into San Rafael," was my
+reply.
+</para>
+
+<para>
+Our voices were raised, and the sound of the altercation brought
+the Chinese out of the cabin.
+</para>
+
+<para>
+"Now will you head for the beach?"
+</para>
+
+<para>
+This from George, and I found myself looking into the muzzle of his
+revolver - of the revolver he dared to use on me, but was too
+cowardly to use on the prisoners.
+</para>
+
+<para>
+My brain seemed smitten with a dazzling brightness.  The whole
+situation, in all its bearings, was focussed sharply before me -
+the shame of losing the prisoners, the worthlessness and cowardice
+of George, the meeting with Le Grant and the other patrol men and
+the lame explanation; and then there was the fight I had fought so
+hard, victory wrenched from me just as I thought I had it within my
+grasp.  And out of the tail of my eye I could see the Chinese
+crowding together by the cabin doors and leering triumphantly.  It
+would never do.
+</para>
+
+<para>
+I threw my hand up and my head down.  The first act elevated the
+muzzle, and the second removed my head from the path of the bullet
+which went whistling past.  One hand closed on George's wrist, the
+other on the revolver.  Yellow Handkerchief and his gang sprang
+toward me.  It was now or never.  Putting all my strength into a
+sudden effort, I swung George's body forward to meet them.  Then I
+pulled back with equal suddenness, ripping the revolver out of his
+fingers and jerking him off his feet.  He fell against Yellow
+Handkerchief's knees, who stumbled over him, and the pair wallowed
+in the bailing hole where the cockpit floor was torn open.  The
+next instant I was covering them with my revolver, and the wild
+shrimp-catchers were cowering and cringing away.
+</para>
+
+<para>
+But I swiftly discovered that there was all the difference in the
+world between shooting men who are attacking and men who are doing
+nothing more than simply refusing to obey.  For obey they would not
+when I ordered them into the bailing hole.  I threatened them with
+the revolver, but they sat stolidly in the flooded cabin and on the
+roof and would not move.
+</para>
+
+<para>
+Fifteen minutes passed, the Reindeer sinking deeper and deeper, her
+mainsail flapping in the calm.  But from off the Point Pedro shore
+I saw a dark line form on the water and travel toward us.  It was
+the steady breeze I had been expecting so long.  I called to the
+Chinese and pointed it out.  They hailed it with exclamations.
+Then I pointed to the sail and to the water in the Reindeer, and
+indicated by signs that when the wind reached the sail, what of the
+water aboard we would capsize.  But they jeered defiantly, for they
+knew it was in my power to luff the helm and let go the main-sheet,
+so as to spill the wind and escape damage.
+</para>
+
+<para>
+But my mind was made up.  I hauled in the main-sheet a foot or two,
+took a turn with it, and bracing my feet, put my back against the
+tiller.  This left me one hand for the sheet and one for the
+revolver.  The dark line drew nearer, and I could see them looking
+from me to it and back again with an apprehension they could not
+successfully conceal.  My brain and will and endurance were pitted
+against theirs, and the problem was which could stand the strain of
+imminent death the longer and not give in.
+</para>
+
+<para>
+Then the wind struck us.  The main-sheet tautened with a brisk
+rattling of the blocks, the boom uplifted, the sail bellied out,
+and the Reindeer heeled over - over, and over, till the lee-rail
+went under, the cabin windows went under, and the bay began to pour
+in over the cockpit rail.  So violently had she heeled over, that
+the men in the cabin had been thrown on top of one another into the
+lee bunk, where they squirmed and twisted and were washed about,
+those underneath being perilously near to drowning.
+</para>
+
+<para>
+The wind freshened a bit, and the Reindeer went over farther than
+ever.  For the moment I thought she was gone, and I knew that
+another puff like that and she surely would go.  While I pressed
+her under and debated whether I should give up or not, the Chinese
+cried for mercy.  I think it was the sweetest sound I have ever
+heard.  And then, and not until then, did I luff up and ease out
+the main-sheet.  The Reindeer righted very slowly, and when she was
+on an even keel was so much awash that I doubted if she could be
+saved.
+</para>
+
+<para>
+But the Chinese scrambled madly into the cockpit and fell to
+bailing with buckets, pots, pans, and everything they could lay
+hands on.  It was a beautiful sight to see that water flying over
+the side!  And when the Reindeer was high and proud on the water
+once more, we dashed away with the breeze on our quarter, and at
+the last possible moment crossed the mud flats and entered the
+slough.
+</para>
+
+<para>
+The spirit of the Chinese was broken, and so docile did they become
+that ere we made San Rafael they were out with the tow-rope, Yellow
+Handkerchief at the head of the line.  As for George, it was his
+last trip with the fish patrol.  He did not care for that sort of
+thing, he explained, and he thought a clerkship ashore was good
+enough for him.  And we thought so too.
+</para>
+
+
+</chapter>
+
+<chapter>
+<title>THE KING OF THE GREEKS</title>
+
+
+<para>
+Big Alec had never been captured by the fish patrol.  It was his
+boast that no man could take him alive, and it was his history that
+of the many men who had tried to take him dead none had succeeded.
+It was also history that at least two patrolmen who had tried to
+take him dead had died themselves.  Further, no man violated the
+fish laws more systematically and deliberately than Big Alec.
+</para>
+
+<para>
+He was called "Big Alec" because of his gigantic stature.  His
+height was six feet three inches, and he was correspondingly broad-
+shouldered and deep-chested.  He was splendidly muscled and hard as
+steel, and there were innumerable stories in circulation among the
+fisher-folk concerning his prodigious strength.  He was as bold and
+dominant of spirit as he was strong of body, and because of this he
+was widely known by another name, that of "The King of the Greeks."
+The fishing population was largely composed of Greeks, and they
+looked up to him and obeyed him as their chief.  And as their
+chief, he fought their fights for them, saw that they were
+protected, saved them from the law when they fell into its
+clutches, and made them stand by one another and himself in time of
+trouble.
+</para>
+
+<para>
+In the old days, the fish patrol had attempted his capture many
+disastrous times and had finally given it over, so that when the
+word was out that he was coming to Benicia, I was most anxious to
+see him.  But I did not have to hunt him up.  In his usual bold
+way, the first thing he did on arriving was to hunt us up.  Charley
+Le Grant and I at the time were under a patrol-man named Carmintel,
+and the three of us were on the Reindeer, preparing for a trip,
+when Big Alec stepped aboard.  Carmintel evidently knew him, for
+they shook hands in recognition.  Big Alec took no notice of
+Charley or me.
+</para>
+
+<para>
+"I've come down to fish sturgeon a couple of months," he said to
+Carmintel.
+</para>
+
+<para>
+His eyes flashed with challenge as he spoke, and we noticed the
+patrolman's eyes drop before him.
+</para>
+
+<para>
+"That's all right, Alec," Carmintel said in a low voice.  "I'll not
+bother you.  Come on into the cabin, and we'll talk things over,"
+he added.
+</para>
+
+<para>
+When they had gone inside and shut the doors after them, Charley
+winked with slow deliberation at me.  But I was only a youngster,
+and new to men and the ways of some men, so I did not understand.
+Nor did Charley explain, though I felt there was something wrong
+about the business.
+</para>
+
+<para>
+Leaving them to their conference, at Charley's suggestion we
+boarded our skiff and pulled over to the Old Steamboat Wharf, where
+Big Alec's ark was lying.  An ark is a house-boat of small though
+comfortable dimensions, and is as necessary to the Upper Bay
+fisherman as are nets and boats.  We were both curious to see Big
+Alec's ark, for history said that it had been the scene of more
+than one pitched battle, and that it was riddled with bullet-holes.
+</para>
+
+<para>
+We found the holes (stopped with wooden plugs and painted over),
+but there were not so many as I had expected.  Charley noted my
+look of disappointment, and laughed; and then to comfort me he gave
+an authentic account of one expedition which had descended upon Big
+Alec's floating home to capture him, alive preferably, dead if
+necessary.  At the end of half a day's fighting, the patrolmen had
+drawn off in wrecked boats, with one of their number killed and
+three wounded.  And when they returned next morning with
+reinforcements they found only the mooring-stakes of Big Alec's
+ark; the ark itself remained hidden for months in the fastnesses of
+the Suisun tules.
+</para>
+
+<para>
+"But why was he not hanged for murder?" I demanded.  "Surely the
+United States is powerful enough to bring such a man to justice."
+</para>
+
+<para>
+"He gave himself up and stood trial," Charley answered.  "It cost
+him fifty thousand dollars to win the case, which he did on
+technicalities and with the aid of the best lawyers in the state.
+Every Greek fisherman on the river contributed to the sum.  Big
+Alec levied and collected the tax, for all the world like a king.
+The United States may be all-powerful, my lad, but the fact remains
+that Big Alec is a king inside the United States, with a country
+and subjects all his own."
+</para>
+
+<para>
+"But what are you going to do about his fishing for sturgeon?  He's
+bound to fish with a 'Chinese line.'"
+</para>
+
+<para>
+Charley shrugged his shoulders.  "We'll see what we will see," he
+said enigmatically.
+</para>
+
+<para>
+Now a "Chinese line" is a cunning device invented by the people
+whose name it bears.  By a simple system of floats, weights, and
+anchors, thousands of hooks, each on a separate leader, are
+suspended at a distance of from six inches to a foot above the
+bottom.  The remarkable thing about such a line is the hook.  It is
+barbless, and in place of the barb, the hook is filed long and
+tapering to a point as sharp as that of a needle.  These hoods are
+only a few inches apart, and when several thousand of them are
+suspended just above the bottom, like a fringe, for a couple of
+hundred fathoms, they present a formidable obstacle to the fish
+that travel along the bottom.
+</para>
+
+<para>
+Such a fish is the sturgeon, which goes rooting along like a pig,
+and indeed is often called "pig-fish."  Pricked by the first hook
+it touches, the sturgeon gives a startled leap and comes into
+contact with half a dozen more hooks.  Then it threshes about
+wildly, until it receives hook after hook in its soft flesh; and
+the hooks, straining from many different angles, hold the luckless
+fish fast until it is drowned.  Because no sturgeon can pass
+through a Chinese line, the device is called a trap in the fish
+laws; and because it bids fair to exterminate the sturgeon, it is
+branded by the fish laws as illegal.  And such a line, we were
+confident, Big Alec intended setting, in open and flagrant
+violation of the law.
+</para>
+
+<para>
+Several days passed after the visit of Big Alec, during which
+Charley and I kept a sharp watch on him.  He towed his ark around
+the Solano Wharf and into the big bight at Turner's Shipyard.  The
+bight we knew to be good ground for sturgeon, and there we felt
+sure the King of the Greeks intended to begin operations.  The tide
+circled like a mill-race in and out of this bight, and made it
+possible to raise, lower, or set a Chinese line only at slack
+water.  So between the tides Charley and I made it a point for one
+or the other of us to keep a lookout from the Solano Wharf.
+</para>
+
+<para>
+On the fourth day I was lying in the sun behind the stringer-piece
+of the wharf, when I saw a skiff leave the distant shore and pull
+out into the bight.  In an instant the glasses were at my eyes and
+I was following every movement of the skiff.  There were two men in
+it, and though it was a good mile away, I made out one of them to
+be Big Alec; and ere the skiff returned to shore I made out enough
+more to know that the Greek had set his line.
+</para>
+
+<para>
+"Big Alec has a Chinese line out in the bight off Turner's
+Shipyard," Charley Le Grant said that afternoon to Carmintel.
+</para>
+
+<para>
+A fleeting expression of annoyance passed over the patrolman's
+face, and then he said, "Yes?" in an absent way, and that was all.
+</para>
+
+<para>
+Charley bit his lip with suppressed anger and turned on his heel.
+</para>
+
+<para>
+"Are you game, my lad?" he said to me later on in the evening, just
+as we finished washing down the Reindeer's decks and were preparing
+to turn in.
+</para>
+
+<para>
+A lump came up in my throat, and I could only nod my head.
+</para>
+
+<para>
+"Well, then," and Charley's eyes glittered in a determined way,
+"we've got to capture Big Alec between us, you and I, and we've got
+to do it in spite of Carmintel.  Will you lend a hand?"
+</para>
+
+<para>
+"It's a hard proposition, but we can do it," he added after a
+pause.
+</para>
+
+<para>
+"Of course we can," I supplemented enthusiastically.
+</para>
+
+<para>
+And then he said, "Of course we can," and we shook hands on it and
+went to bed.
+</para>
+
+<para>
+But it was no easy task we had set ourselves.  In order to convict
+a man of illegal fishing, it was necessary to catch him in the act
+with all the evidence of the crime about him - the hooks, the
+lines, the fish, and the man himself.  This meant that we must take
+Big Alec on the open water, where he could see us coming and
+prepare for us one of the warm receptions for which he was noted.
+</para>
+
+<para>
+"There's no getting around it," Charley said one morning.  "If we
+can only get alongside it's an even toss, and there's nothing left
+for us but to try and get alongside.  Come on, lad."
+</para>
+
+<para>
+We were in the Columbia River salmon boat, the one we had used
+against the Chinese shrimp-catchers.  Slack water had come, and as
+we dropped around the end of the Solano Wharf we saw Big Alec at
+work, running his line and removing the fish.
+</para>
+
+<para>
+"Change places," Charley commanded, "and steer just astern of him
+as though you're going into the shipyard."
+</para>
+
+<para>
+I took the tiller, and Charley sat down on a thwart amidships,
+placing his revolver handily beside him.
+</para>
+
+<para>
+"If he begins to shoot," he cautioned, "get down in the bottom and
+steer from there, so that nothing more than your hand will be
+exposed."
+</para>
+
+<para>
+I nodded, and we kept silent after that, the boat slipping gently
+through the water and Big Alec growing nearer and nearer.  We could
+see him quite plainly, gaffing the sturgeon and throwing them into
+the boat while his companion ran the line and cleared the hooks as
+he dropped them back into the water.  Nevertheless, we were five
+hundred yards away when the big fisherman hailed us.
+</para>
+
+<para>
+"Here!  You!  What do you want?" he shouted.
+</para>
+
+<para>
+"Keep going," Charley whispered, "just as though you didn't hear
+him."
+</para>
+
+<para>
+The next few moments were very anxious ones.  The fisherman was
+studying us sharply, while we were gliding up on him every second.
+</para>
+
+<para>
+"You keep off if you know what's good for you!" he called out
+suddenly, as though he had made up his mind as to who and what we
+were.  "If you don't, I'll fix you!"
+</para>
+
+<para>
+He brought a rifle to his shoulder and trained it on me.
+</para>
+
+<para>
+"Now will you keep off?" he demanded.
+</para>
+
+<para>
+I could hear Charley groan with disappointment.  "Keep off," he
+whispered; "it's all up for this time."
+</para>
+
+<para>
+I put up the tiller and eased the sheet, and the salmon boat ran
+off five or six points.  Big Alec watched us till we were out of
+range, when he returned to his work.
+</para>
+
+<para>
+"You'd better leave Big Alec alone," Carmintel said, rather sourly,
+to Charley that night.
+</para>
+
+<para>
+"So he's been complaining to you, has he?"  Charley said
+significantly.
+</para>
+
+<para>
+Carmintel flushed painfully.  "You'd better leave him alone, I tell
+you," he repeated.  "He's a dangerous man, and it won't pay to fool
+with him."
+</para>
+
+<para>
+"Yes," Charley answered softly; "I've heard that it pays better to
+leave him alone."
+</para>
+
+<para>
+This was a direct thrust at Carmintel, and we could see by the
+expression of his face that it sank home.  For it was common
+knowledge that Big Alec was as willing to bribe as to fight, and
+that of late years more than one patrolman had handled the
+fisherman's money.
+</para>
+
+<para>
+"Do you mean to say - " Carmintel began, in a bullying tone.
+</para>
+
+<para>
+But Charley cut him off shortly.  "I mean to say nothing," he said.
+"You heard what I said, and if the cap fits, why - "
+</para>
+
+<para>
+He shrugged his shoulders, and Carmintel glowered at him,
+speechless.
+</para>
+
+<para>
+"What we want is imagination," Charley said to me one day, when we
+had attempted to creep upon Big Alec in the gray of dawn and had
+been shot at for our trouble.
+</para>
+
+<para>
+And thereafter, and for many days, I cudgelled my brains trying to
+imagine some possible way by which two men, on an open stretch of
+water, could capture another who knew how to use a rifle and was
+never to be found without one.  Regularly, every slack water,
+without slyness, boldly and openly in the broad day, Big Alec was
+to be seen running his line.  And what made it particularly
+exasperating was the fact that every fisherman, from Benicia to
+Vallejo knew that he was successfully defying us.  Carmintel also
+bothered us, for he kept us busy among the shad-fishers of San
+Pablo, so that we had little time to spare on the King of the
+Greeks.  But Charley's wife and children lived at Benicia, and we
+had made the place our headquarters, so that we always returned to
+it.
+</para>
+
+<para>
+"I'll tell you what we can do," I said, after several fruitless
+weeks had passed; "we can wait some slack water till Big Alec has
+run his line and gone ashore with the fish, and then we can go out
+and capture the line.  It will put him to time and expense to make
+another, and then we'll figure to capture that too.  If we can't
+capture him, we can discourage him, you see."
+</para>
+
+<para>
+Charley saw, and said it wasn't a bad idea.  We watched our chance,
+and the next low-water slack, after Big Alec had removed the fish
+from the line and returned ashore, we went out in the salmon boat.
+We had the bearings of the line from shore marks, and we knew we
+would have no difficulty in locating it.  The first of the flood
+tide was setting in, when we ran below where we thought the line
+was stretched and dropped over a fishing-boat anchor.  Keeping a
+short rope to the anchor, so that it barely touched the bottom, we
+dragged it slowly along until it stuck and the boat fetched up hard
+and fast.
+</para>
+
+<para>
+"We've got it," Charley cried.  "Come on and lend a hand to get it
+in."
+</para>
+
+<para>
+Together we hove up the rope till the anchor I came in sight with
+the sturgeon line caught across one of the flukes.  Scores of the
+murderous-looking hooks flashed into sight as we cleared the
+anchor, and we had just started to run along the line to the end
+where we could begin to lift it, when a sharp thud in the boat
+startled us.  We looked about, but saw nothing and returned to our
+work.  An instant later there was a similar sharp thud and the
+gunwale splintered between Charley's body and mine.
+</para>
+
+<para>
+"That's remarkably like a bullet, lad," he said reflectively.  "And
+it's a long shot Big Alec's making."
+</para>
+
+<para>
+"And he's using smokeless powder," he concluded, after an
+examination of the mile-distant shore.  "That's why we can't hear
+the report."
+</para>
+
+<para>
+I looked at the shore, but could see no sign of Big Alec, who was
+undoubtedly hidden in some rocky nook with us at his mercy.  A
+third bullet struck the water, glanced, passed singing over our
+heads, and struck the water again beyond.
+</para>
+
+<para>
+"I guess we'd better get out of this," Charley remarked coolly.
+"What do you think, lad?"
+</para>
+
+<para>
+I thought so, too, and said we didn't want the line anyway.
+Whereupon we cast off and hoisted the spritsail.  The bullets
+ceased at once, and we sailed away, unpleasantly confident that Big
+Alec was laughing at our discomfiture.
+</para>
+
+<para>
+And more than that, the next day on the fishing wharf, where we
+were inspecting nets, he saw fit to laugh and sneer at us, and this
+before all the fishermen.  Charley's face went black with anger;
+but beyond promising Big Alec that in the end he would surely land
+him behind the bars, he controlled himself and said nothing.  The
+King of the Greeks made his boast that no fish patrol had ever
+taken him or ever could take him, and the fishermen cheered him and
+said it was true.  They grew excited, and it looked like trouble
+for a while; but Big Alec asserted his kingship and quelled them.
+</para>
+
+<para>
+Carmintel also laughed at Charley, and dropped sarcastic remarks,
+and made it hard for him.  But Charley refused to be angered,
+though he told me in confidence that he intended to capture Big
+Alec if it took all the rest of his life to accomplish it.
+</para>
+
+<para>
+"I don't know how I'll do it," he said, "but do it I will, as sure
+as I am Charley Le Grant.  The idea will come to me at the right
+and proper time, never fear."
+</para>
+
+<para>
+And at the right time it came, and most unexpectedly.  Fully a
+month had passed, and we were constantly up and down the river, and
+down and up the bay, with no spare moments to devote to the
+particular fisherman who ran a Chinese line in the bight of
+Turner's Shipyard.  We had called in at Selby's Smelter one
+afternoon, while on patrol work, when all unknown to us our
+opportunity happened along.  It appeared in the guise of a helpless
+yacht loaded with seasick people, so we could hardly be expected to
+recognize it as the opportunity.  It was a large sloop-yacht, and
+it was helpless inasmuch as the trade-wind was blowing half a gale
+and there were no capable sailors aboard.
+</para>
+
+<para>
+From the wharf at Selby's we watched with careless interest the
+lubberly manoeuvre performed of bringing the yacht to anchor, and
+the equally lubberly manoeuvre of sending the small boat ashore.  A
+very miserable-looking man in draggled ducks, after nearly swamping
+the boat in the heavy seas, passed us the painter and climbed out.
+He staggered about as though the wharf were rolling, and told us
+his troubles, which were the troubles of the yacht.  The only
+rough-weather sailor aboard, the man on whom they all depended, had
+been called back to San Francisco by a telegram, and they had
+attempted to continue the cruise alone.  The high wind and big seas
+of San Pablo Bay had been too much for them; all hands were sick,
+nobody knew anything or could do anything; and so they had run in
+to the smelter either to desert the yacht or to get somebody to
+bring it to Benicia.  In short, did we know of any sailors who
+would bring the yacht into Benicia?
+</para>
+
+<para>
+Charley looked at me.  The Reindeer was lying in a snug place.  We
+had nothing on hand in the way of patrol work till midnight.  With
+the wind then blowing, we could sail the yacht into Benicia in a
+couple of hours, have several more hours ashore, and come back to
+the smelter on the evening train.
+</para>
+
+<para>
+"All right, captain," Charley said to the disconsolate yachtsman,
+who smiled in sickly fashion at the title.
+</para>
+
+<para>
+"I'm only the owner," he explained.
+</para>
+
+<para>
+We rowed him aboard in much better style than he had come ashore,
+and saw for ourselves the helplessness of the passengers.  There
+were a dozen men and women, and all of them too sick even to appear
+grateful at our coming.  The yacht was rolling savagely, broad on,
+and no sooner had the owner's feet touched the deck than he
+collapsed and joined, the others.  Not one was able to bear a hand,
+so Charley and I between us cleared the badly tangled running gear,
+got up sail, and hoisted anchor.
+</para>
+
+<para>
+It was a rough trip, though a swift one.  The Carquinez Straits
+were a welter of foam and smother, and we came through them wildly
+before the wind, the big mainsail alternately dipping and flinging
+its boom skyward as we tore along.  But the people did not mind.
+They did not mind anything.  Two or three, including the owner,
+sprawled in the cockpit, shuddering when the yacht lifted and raced
+and sank dizzily into the trough, and between-whiles regarding the
+shore with yearning eyes.  The rest were huddled on the cabin floor
+among the cushions.  Now and again some one groaned, but for the
+most part they were as limp as so many dead persons.
+</para>
+
+<para>
+As the bight at Turner's Shipyard opened out, Charley edged into it
+to get the smoother water.  Benicia was in view, and we were
+bowling along over comparatively easy water, when a speck of a boat
+danced up ahead of us, directly in our course.  It was low-water
+slack.  Charley and I looked at each other.  No word was spoken,
+but at once the yacht began a most astonishing performance, veering
+and yawing as though the greenest of amateurs was at the wheel.  It
+was a sight for sailormen to see.  To all appearances, a runaway
+yacht was careering madly over the bight, and now and again
+yielding a little bit to control in a desperate effort to make
+Benicia.
+</para>
+
+<para>
+The owner forgot his seasickness long enough to look anxious.  The
+speck of a boat grew larger and larger, till we could see Big Alec
+and his partner, with a turn of the sturgeon line around a cleat,
+resting from their labor to laugh at us.  Charley pulled his
+sou'wester over his eyes, and I followed his example, though I
+could not guess the idea he evidently had in mind and intended to
+carry into execution.
+</para>
+
+<para>
+We came foaming down abreast of the skiff, so close that we could
+hear above the wind the voices of Big Alec and his mate as they
+shouted at us with all the scorn that professional watermen feel
+for amateurs, especially when amateurs are making fools of
+themselves.
+</para>
+
+<para>
+We thundered on past the fishermen, and nothing had happened.
+Charley grinned at the disappointment he saw in my face, and then
+shouted:
+</para>
+
+<para>
+"Stand by the main-sheet to jibe!"
+</para>
+
+<para>
+He put the wheel hard over, and the yacht whirled around
+obediently.  The main-sheet slacked and dipped, then shot over our
+heads after the boom and tautened with a crash on the traveller.
+The yacht heeled over almost on her beam ends, and a great wail
+went up from the seasick passengers as they swept across the cabin
+floor in a tangled mass and piled into a heap in the starboard
+bunks.
+</para>
+
+<para>
+But we had no time for them.  The yacht, completing the manoeuvre,
+headed into the wind with slatting canvas, and righted to an even
+keel.  We were still plunging ahead, and directly in our path was
+the skiff.  I saw Big Alec dive overboard and his mate leap for our
+bowsprit.  Then came the crash as we struck the boat, and a series
+of grinding bumps as it passed under our bottom.
+</para>
+
+<para>
+"That fixes his rifle," I heard Charley mutter, as he sprang upon
+the deck to look for Big Alec somewhere astern.
+</para>
+
+<para>
+The wind and sea quickly stopped our forward movement, and we began
+to drift backward over the spot where the skiff had been.  Big
+Alec's black head and swarthy face popped up within arm's reach;
+and all unsuspecting and very angry with what he took to be the
+clumsiness of amateur sailors, he was hauled aboard.  Also he was
+out of breath, for he had dived deep and stayed down long to escape
+our keel.
+</para>
+
+<para>
+The next instant, to the perplexity and consternation of the owner,
+Charley was on top of Big Alec in the cockpit, and I was helping
+bind him with gaskets.  The owner was dancing excitedly about and
+demanding an explanation, but by that time Big Alec's partner had
+crawled aft from the bowsprit and was peering apprehensively over
+the rail into the cockpit.  Charley's arm shot around his neck and
+the man landed on his back beside Big Alec.
+</para>
+
+<para>
+"More gaskets!" Charley shouted, and I made haste to supply them.
+</para>
+
+<para>
+The wrecked skiff was rolling sluggishly a short distance to
+windward, and I trimmed the sheets while Charley took the wheel and
+steered for it.
+</para>
+
+<para>
+"These two men are old offenders," he explained to the angry owner;
+"and they are most persistent violators of the fish and game laws.
+You have seen them caught in the act, and you may expect to be
+subpoenaed as witness for the state when the trial comes off."
+</para>
+
+<para>
+As he spoke he rounded alongside the skiff.  It had been torn from
+the line, a section of which was dragging to it.  He hauled in
+forty or fifty feet with a young sturgeon still fast in a tangle of
+barbless hooks, slashed that much of the line free with his knife,
+and tossed it into the cockpit beside the prisoners.
+</para>
+
+<para>
+"And there's the evidence, Exhibit A, for the people," Charley
+continued.  "Look it over carefully so that you may identify it in
+the court-room with the time and place of capture."
+</para>
+
+<para>
+And then, in triumph, with no more veering and yawing, we sailed
+into Benicia, the King of the Greeks bound hard and fast in the
+cockpit, and for the first time in his life a prisoner of the fish
+patrol.
+</para>
+
+
+</chapter>
+
+<chapter>
+<title>A RAID ON THE OYSTER PIRATES</title>
+
+
+<para>
+Of the fish patrolmen under whom we served at various times,
+Charley Le Grant and I were agreed, I think, that Neil Partington
+was the best.  He was neither dishonest nor cowardly; and while he
+demanded strict obedience when we were under his orders, at the
+same time our relations were those of easy comradeship, and he
+permitted us a freedom to which we were ordinarily unaccustomed, as
+the present story will show.
+</para>
+
+<para>
+Neil's family lived in Oakland, which is on the Lower Bay, not more
+than six miles across the water from San Francisco.  One day, while
+scouting among the Chinese shrimp-catchers of Point Pedro, he
+received word that his wife was very ill; and within the hour the
+Reindeer was bowling along for Oakland, with a stiff northwest
+breeze astern.  We ran up the Oakland Estuary and came to anchor,
+and in the days that followed, while Neil was ashore, we tightened
+up the Reindeer's rigging, overhauled the ballast, scraped down,
+and put the sloop into thorough shape.
+</para>
+
+<para>
+This done, time hung heavy on our hands.  Neil's wife was
+dangerously ill, and the outlook was a week's lie-over, awaiting
+the crisis.  Charley and I roamed the docks, wondering what we
+should do, and so came upon the oyster fleet lying at the Oakland
+City Wharf.  In the main they were trim, natty boats, made for
+speed and bad weather, and we sat down on the stringer-piece of the
+dock to study them.
+</para>
+
+<para>
+"A good catch, I guess," Charley said, pointing to the heaps of
+oysters, assorted in three sizes, which lay upon their decks.
+</para>
+
+<para>
+Pedlers were backing their wagons to the edge of the wharf, and
+from the bargaining and chaffering that went on, I managed to learn
+the selling price of the oysters.
+</para>
+
+<para>
+"That boat must have at least two hundred dollars' worth aboard," I
+calculated.  "I wonder how long it took to get the load?"
+</para>
+
+<para>
+"Three or four days," Charley answered.  "Not bad wages for two men
+- twenty-five dollars a day apiece."
+</para>
+
+<para>
+The boat we were discussing, the Ghost, lay directly beneath us.
+Two men composed its crew.  One was a squat, broad-shouldered
+fellow with remarkably long and gorilla-like arms, while the other
+was tall and well proportioned, with clear blue eyes and a mat of
+straight black hair.  So unusual and striking was this combination
+of hair and eyes that Charley and I remained somewhat longer than
+we intended.
+</para>
+
+<para>
+And it was well that we did.  A stout, elderly man, with the dress
+and carriage of a successful merchant, came up and stood beside us,
+looking down upon the deck of the Ghost.  He appeared angry, and
+the longer he looked the angrier he grew.
+</para>
+
+<para>
+"Those are my oysters," he said at last.  "I know they are my
+oysters.  You raided my beds last night and robbed me of them."
+</para>
+
+<para>
+The tall man and the short man on the Ghost looked up.
+</para>
+
+<para>
+"Hello, Taft," the short man said, with insolent familiarity.
+(Among the bayfarers he had gained the nickname of "The Centipede"
+on account of his long arms.)  "Hello, Taft," he repeated, with the
+same touch of insolence.  "Wot 'r you growling about now?"
+</para>
+
+<para>
+"Those are my oysters - that's what I said.  You've stolen them
+from my beds."
+</para>
+
+<para>
+"Yer mighty wise, ain't ye?" was the Centipede's sneering reply.
+"S'pose you can tell your oysters wherever you see 'em?"
+</para>
+
+<para>
+"Now, in my experience," broke in the tall man, "oysters is oysters
+wherever you find 'em, an' they're pretty much alike all the Bay
+over, and the world over, too, for that matter.  We're not wantin'
+to quarrel with you, Mr. Taft, but we jes' wish you wouldn't
+insinuate that them oysters is yours an' that we're thieves an'
+robbers till you can prove the goods."
+</para>
+
+<para>
+"I know they're mine; I'd stake my life on it!" Mr. Taft snorted.
+</para>
+
+<para>
+"Prove it," challenged the tall man, who we afterward learned was
+known as "The Porpoise" because of his wonderful swimming
+abilities.
+</para>
+
+<para>
+Mr. Taft shrugged his shoulders helplessly.  Of course he could not
+prove the oysters to be his, no matter how certain he might be.
+</para>
+
+<para>
+"I'd give a thousand dollars to have you men behind the bars!" he
+cried.  "I'll give fifty dollars a head for your arrest and
+conviction, all of you!"
+</para>
+
+<para>
+A roar of laughter went up from the different boats, for the rest
+of the pirates had been listening to the discussion.
+</para>
+
+<para>
+"There's more money in oysters," the Porpoise remarked dryly.
+</para>
+
+<para>
+Mr. Taft turned impatiently on his heel and walked away.  From out
+of the corner of his eye, Charley noted the way he went.  Several
+minutes later, when he had disappeared around a corner, Charley
+rose lazily to his feet.  I followed him, and we sauntered off in
+the opposite direction to that taken by Mr. Taft.
+</para>
+
+<para>
+"Come on!  Lively!" Charley whispered, when we passed from the view
+of the oyster fleet.
+</para>
+
+<para>
+Our course was changed at once, and we dodged around corners and
+raced up and down side-streets till Mr. Taft's generous form loomed
+up ahead of us.
+</para>
+
+<para>
+"I'm going to interview him about that reward," Charley explained,
+as we rapidly over-hauled the oyster-bed owner.  "Neil will be
+delayed here for a week, and you and I might as well be doing
+something in the meantime.  What do you say?"
+</para>
+
+<para>
+"Of course, of course," Mr. Taft said, when Charley had introduced
+himself and explained his errand.  "Those thieves are robbing me of
+thousands of dollars every year, and I shall be glad to break them
+up at any price, - yes, sir, at any price.  As I said, I'll give
+fifty dollars a head, and call it cheap at that.  They've robbed my
+beds, torn down my signs, terrorized my watchmen, and last year
+killed one of them.  Couldn't prove it.  All done in the blackness
+of night.  All I had was a dead watchman and no evidence.  The
+detectives could do nothing.  Nobody has been able to do anything
+with those men.  We have never succeeded in arresting one of them.
+So I say, Mr. -  What did you say your name was?"
+</para>
+
+<para>
+"Le Grant," Charley answered.
+</para>
+
+<para>
+"So I say, Mr. Le Grant, I am deeply obliged to you for the
+assistance you offer.  And I shall be glad, most glad, sir, to co-
+operate with you in every way.  My watchmen and boats are at your
+disposal.  Come and see me at the San Francisco offices any time,
+or telephone at my expense.  And don't be afraid of spending money.
+I'll foot your expenses, whatever they are, so long as they are
+within reason.  The situation is growing desperate, and something
+must be done to determine whether I or that band of ruffians own
+those oyster beds."
+</para>
+
+<para>
+"Now we'll see Neil," Charley said, when he had seen Mr. Taft upon
+his train to San Francisco.
+</para>
+
+<para>
+Not only did Neil Partington interpose no obstacle to our
+adventure, but he proved to be of the greatest assistance.  Charley
+and I knew nothing of the oyster industry, while his head was an
+encyclopaedia of facts concerning it.  Also, within an hour or so,
+he was able to bring to us a Greek boy of seventeen or eighteen who
+knew thoroughly well the ins and outs of oyster piracy.
+</para>
+
+<para>
+At this point I may as well explain that we of the fish patrol were
+free lances in a way.  While Neil Partington, who was a patrolman
+proper, received a regular salary, Charley and I, being merely
+deputies, received only what we earned - that is to say, a certain
+percentage of the fines imposed on convicted violators of the fish
+laws.  Also, any rewards that chanced our way were ours.  We
+offered to share with Partington whatever we should get from Mr.
+Taft, but the patrolman would not hear of it.  He was only too
+happy, he said, to do a good turn for us, who had done so many for
+him.
+</para>
+
+<para>
+We held a long council of war, and mapped out the following line of
+action.  Our faces were unfamiliar on the Lower Bay, but as the
+Reindeer was well known as a fish-patrol sloop, the Greek boy,
+whose name was Nicholas, and I were to sail some innocent-looking
+craft down to Asparagus Island and join the oyster pirates' fleet.
+Here, according to Nicholas's description of the beds and the
+manner of raiding, it was possible for us to catch the pirates in
+the act of stealing oysters, and at the same time to get them in
+our power.  Charley was to be on the shore, with Mr. Taft's
+watchmen and a posse of constables, to help us at the right time.
+</para>
+
+<para>
+"I know just the boat," Neil said, at the conclusion of the
+discussion, "a crazy old sloop that's lying over at Tiburon.  You
+and Nicholas can go over by the ferry, charter it for a song, and
+sail direct for the beds."
+</para>
+
+<para>
+"Good luck be with you, boys," he said at parting, two days later.
+"Remember, they are dangerous men, so be careful."
+</para>
+
+<para>
+Nicholas and I succeeded in chartering the sloop very cheaply; and
+between laughs, while getting up sail, we agreed that she was even
+crazier and older than she had been described.  She was a big,
+flat-bottomed, square-sterned craft, sloop-rigged, with a sprung
+mast, slack rigging, dilapidated sails, and rotten running-gear,
+clumsy to handle and uncertain in bringing about, and she smelled
+vilely of coal tar, with which strange stuff she had been smeared
+from stem to stern and from cabin-roof to centreboard.  And to cap
+it all, Coal Tar Maggie was printed in great white letters the
+whole length of either side.
+</para>
+
+<para>
+It was an uneventful though laughable run from Tiburon to Asparagus
+Island, where we arrived in the afternoon of the following day.
+The oyster pirates, a fleet of a dozen sloops, were lying at anchor
+on what was known as the "Deserted Beds."  The Coal Tar Maggie came
+sloshing into their midst with a light breeze astern, and they
+crowded on deck to see us.  Nicholas and I had caught the spirit of
+the crazy craft, and we handled her in most lubberly fashion.
+</para>
+
+<para>
+"Wot is it?" some one called.
+</para>
+
+<para>
+"Name it 'n' ye kin have it!" called another.
+</para>
+
+<para>
+"I swan naow, ef it ain't the old Ark itself!" mimicked the
+Centipede from the deck of the Ghost.
+</para>
+
+<para>
+"Hey!  Ahoy there, clipper ship!" another wag shouted.  "Wot's yer
+port?"
+</para>
+
+<para>
+We took no notice of the joking, but acted, after the manner of
+greenhorns, as though the Coal Tar Maggie required our undivided
+attention.  I rounded her well to windward of the Ghost, and
+Nicholas ran for'ard to drop the anchor.  To all appearances it was
+a bungle, the way the chain tangled and kept the anchor from
+reaching the bottom.  And to all appearances Nicholas and I were
+terribly excited as we strove to clear it.  At any rate, we quite
+deceived the pirates, who took huge delight in our predicament.
+</para>
+
+<para>
+But the chain remained tangled, and amid all kinds of mocking
+advice we drifted down upon and fouled the Ghost, whose bowsprit
+poked square through our mainsail and ripped a hole in it as big as
+a barn door.  The Centipede and the Porpoise doubled up on the
+cabin in paroxysms of laughter, and left us to get clear as best we
+could.  This, with much unseaman-like performance, we succeeded in
+doing, and likewise in clearing the anchor-chain, of which we let
+out about three hundred feet.  With only ten feet of water under
+us, this would permit the Coal Tar Maggie to swing in a circle six
+hundred feet in diameter, in which circle she would be able to foul
+at least half the fleet.
+</para>
+
+<para>
+The oyster pirates lay snugly together at short hawsers, the
+weather being fine, and they protested loudly at our ignorance in
+putting out such an unwarranted length of anchor-chain.  And not
+only did they protest, for they made us heave it in again, all but
+thirty feet.
+</para>
+
+<para>
+Having sufficiently impressed them with our general lubberliness,
+Nicholas and I went below to congratulate ourselves and to cook
+supper.  Hardly had we finished the meal and washed the dishes,
+when a skiff ground against the Coal Tar Maggie's side, and heavy
+feet trampled on deck.  Then the Centipede's brutal face appeared
+in the companionway, and he descended into the cabin, followed by
+the Porpoise.  Before they could seat themselves on a bunk, another
+skiff came alongside, and another, and another, till the whole
+fleet was represented by the gathering in the cabin.
+</para>
+
+<para>
+"Where'd you swipe the old tub?" asked a squat and hairy man, with
+cruel eyes and Mexican features.
+</para>
+
+<para>
+"Didn't swipe it," Nicholas answered, meeting them on their own
+ground and encouraging the idea that we had stolen the Coal Tar
+Maggie.  "And if we did, what of it?"
+</para>
+
+<para>
+"Well, I don't admire your taste, that's all," sneered he of the
+Mexican features.  "I'd rot on the beach first before I'd take a
+tub that couldn't get out of its own way."
+</para>
+
+<para>
+"How were we to know till we tried her?" Nicholas asked, so
+innocently as to cause a laugh.  "And how do you get the oysters?"
+he hurried on.  "We want a load of them; that's what we came for, a
+load of oysters."
+</para>
+
+<para>
+"What d'ye want 'em for?" demanded the Porpoise.
+</para>
+
+<para>
+"Oh, to give away to our friends, of course," Nicholas retorted.
+"That's what you do with yours, I suppose."
+</para>
+
+<para>
+This started another laugh, and as our visitors grew more genial we
+could see that they had not the slightest suspicion of our identity
+or purpose.
+</para>
+
+<para>
+"Didn't I see you on the dock in Oakland the other day?" the
+Centipede asked suddenly of me.
+</para>
+
+<para>
+"Yep," I answered boldly, taking the bull by the horns.  "I was
+watching you fellows and figuring out whether we'd go oystering or
+not.  It's a pretty good business, I calculate, and so we're going
+in for it.  That is," I hastened to add, "if you fellows don't
+mind."
+</para>
+
+<para>
+"I'll tell you one thing, which ain't two things," he replied, "and
+that is you'll have to hump yerself an' get a better boat.  We
+won't stand to be disgraced by any such box as this.  Understand?"
+</para>
+
+<para>
+"Sure," I said.  "Soon as we sell some oysters we'll outfit in
+style."
+</para>
+
+<para>
+"And if you show yerself square an' the right sort," he went on,
+"why, you kin run with us.  But if you don't" (here his voice
+became stern and menacing), "why, it'll be the sickest day of yer
+life.  Understand?"
+</para>
+
+<para>
+"Sure," I said.
+</para>
+
+<para>
+After that and more warning and advice of similar nature, the
+conversation became general, and we learned that the beds were to
+be raided that very night.  As they got into their boats, after an
+hour's stay, we were invited to join them in the raid with the
+assurance of "the more the merrier."
+</para>
+
+<para>
+"Did you notice that short, Mexican-looking chap?" Nicholas asked,
+when they had departed to their various sloops.  "He's Barchi, of
+the Sporting Life Gang, and the fellow that came with him is
+Skilling.  They're both out now on five thousand dollars' bail."
+</para>
+
+<para>
+I had heard of the Sporting Life Gang before, a crowd of hoodlums
+and criminals that terrorized the lower quarters of Oakland, and
+two-thirds of which were usually to be found in state's prison for
+crimes that ranged from perjury and ballot-box stuffing to murder.
+</para>
+
+<para>
+"They are not regular oyster pirates," Nicholas continued.
+"They've just come down for the lark and to make a few dollars.
+But we'll have to watch out for them."
+</para>
+
+<para>
+We sat in the cockpit and discussed the details of our plan till
+eleven o'clock had passed, when we heard the rattle of an oar in a
+boat from the direction of the Ghost.  We hauled up our own skiff,
+tossed in a few sacks, and rowed over.  There we found all the
+skiffs assembling, it being the intention to raid the beds in a
+body.
+</para>
+
+<para>
+To my surprise, I found barely a foot of water where we had dropped
+anchor in ten feet.  It was the big June run-out of the full moon,
+and as the ebb had yet an hour and a half to run, I knew that our
+anchorage would be dry ground before slack water.
+</para>
+
+<para>
+Mr. Taft's beds were three miles away, and for a long time we rowed
+silently in the wake of the other boats, once in a while grounding
+and our oar blades constantly striking bottom.  At last we came
+upon soft mud covered with not more than two inches of water - not
+enough to float the boats.  But the pirates at once were over the
+side, and by pushing and pulling on the flat-bottomed skiffs, we
+moved steadily along.
+</para>
+
+<para>
+The full moon was partly obscured by high-flying clouds, but the
+pirates went their way with the familiarity born of long practice.
+After half a mile of the mud, we came upon a deep channel, up which
+we rowed, with dead oyster shoals looming high and dry on either
+side.  At last we reached the picking grounds.  Two men, on one of
+the shoals, hailed us and warned us off.  But the Centipede, the
+Porpoise, Barchi, and Skilling took the lead, and followed by the
+rest of us, at least thirty men in half as many boats, rowed right
+up to the watchmen.
+</para>
+
+<para>
+"You'd better slide outa this here," Barchi said threateningly, "or
+we'll fill you so full of holes you wouldn't float in molasses."
+</para>
+
+<para>
+The watchmen wisely retreated before so overwhelming a force, and
+rowed their boat along the channel toward where the shore should
+be.  Besides, it was in the plan for them to retreat.
+</para>
+
+<para>
+We hauled the noses of the boats up on the shore side of a big
+shoal, and all hands, with sacks, spread out and began picking.
+Every now and again the clouds thinned before the face of the moon,
+and we could see the big oysters quite distinctly.  In almost no
+time sacks were filled and carried back to the boats, where fresh
+ones were obtained.  Nicholas and I returned often and anxiously to
+the boats with our little loads, but always found some one of the
+pirates coming or going.
+</para>
+
+<para>
+"Never mind," he said; "no hurry.  As they pick farther and farther
+away, it will take too long to carry to the boats.  Then they'll
+stand the full sacks on end and pick them up when the tide comes in
+and the skiffs will float to them."
+</para>
+
+<para>
+Fully half an hour went by, and the tide had begun to flood, when
+this came to pass.  Leaving the pirates at their work, we stole
+back to the boats.  One by one, and noiselessly, we shoved them off
+and made them fast in an awkward flotilla.  Just as we were shoving
+off the last skiff, our own, one of the men came upon us.  It was
+Barchi.  His quick eye took in the situation at a glance, and he
+sprang for us; but we went clear with a mighty shove, and he was
+left floundering in the water over his head.  As soon as he got
+back to the shoal he raised his voice and gave the alarm.
+</para>
+
+<para>
+We rowed with all our strength, but it was slow going with so many
+boats in tow.  A pistol cracked from the shoal, a second, and a
+third; then a regular fusillade began.  The bullets spat and spat
+all about us; but thick clouds had covered the moon, and in the dim
+darkness it was no more than random firing.  It was only by chance
+that we could be hit.
+</para>
+
+<para>
+"Wish we had a little steam launch," I panted.
+</para>
+
+<para>
+"I'd just as soon the moon stayed hidden," Nicholas panted back.
+</para>
+
+<para>
+It was slow work, but every stroke carried us farther away from the
+shoal and nearer the shore, till at last the shooting died down,
+and when the moon did come out we were too far away to be in
+danger.  Not long afterward we answered a shoreward hail, and two
+Whitehall boats, each pulled by three pairs of oars, darted up to
+us.  Charley's welcome face bent over to us, and he gripped us by
+the hands while he cried, "Oh, you joys!  You joys!  Both of you!"
+</para>
+
+<para>
+When the flotilla had been landed, Nicholas and I and a watchman
+rowed out in one of the Whitehalls, with Charley in the stern-
+sheets.  Two other Whitehalls followed us, and as the moon now
+shone brightly, we easily made out the oyster pirates on their
+lonely shoal.  As we drew closer, they fired a rattling volley from
+their revolvers, and we promptly retreated beyond range.
+</para>
+
+<para>
+"Lot of time," Charley said.  "The flood is setting in fast, and by
+the time it's up to their necks there won't be any fight left in
+them."
+</para>
+
+<para>
+So we lay on our oars and waited for the tide to do its work.  This
+was the predicament of the pirates:  because of the big run-out,
+the tide was now rushing back like a mill-race, and it was
+impossible for the strongest swimmer in the world to make against
+it the three miles to the sloops.  Between the pirates and the
+shore were we, precluding escape in that direction.  On the other
+hand, the water was rising rapidly over the shoals, and it was only
+a question of a few hours when it would be over their heads.
+</para>
+
+<para>
+It was beautifully calm, and in the brilliant white moonlight we
+watched them through our night glasses and told Charley of the
+voyage of the Coal Tar Maggie.  One o'clock came, and two o'clock,
+and the pirates were clustering on the highest shoal, waist-deep in
+water.
+</para>
+
+<para>
+"Now this illustrates the value of imagination," Charley was
+saying.  "Taft has been trying for years to get them, but he went
+at it with bull strength and failed.  Now we used our heads . . ."
+</para>
+
+<para>
+Just then I heard a scarcely audible gurgle of water, and holding
+up my hand for silence, I turned and pointed to a ripple slowly
+widening out in a growing circle.  It was not more than fifty feet
+from us.  We kept perfectly quiet and waited.  After a minute the
+water broke six feet away, and a black head and white shoulder
+showed in the moonlight.  With a snort of surprise and of suddenly
+expelled breath, the head and shoulder went down.
+</para>
+
+<para>
+We pulled ahead several strokes and drifted with the current.  Four
+pairs of eyes searched the surface of the water, but never another
+ripple showed, and never another glimpse did we catch of the black
+head and white shoulder.
+</para>
+
+<para>
+"It's the Porpoise," Nicholas said.  "It would take broad daylight
+for us to catch him."
+</para>
+
+<para>
+At a quarter to three the pirates gave their first sign of
+weakening.  We heard cries for help, in the unmistakable voice of
+the Centipede, and this time, on rowing closer, we were not fired
+upon.  The Centipede was in a truly perilous plight.  Only the
+heads and shoulders of his fellow-marauders showed above the water
+as they braced themselves against the current, while his feet were
+off the bottom and they were supporting him.
+</para>
+
+<para>
+"Now, lads," Charley said briskly, "we have got you, and you can't
+get away.  If you cut up rough, we'll have to leave you alone and
+the water will finish you.  But if you're good we'll take you
+aboard, one man at a time, and you'll all be saved.  What do you
+say?"
+</para>
+
+<para>
+"Ay," they chorused hoarsely between their chattering teeth.
+</para>
+
+<para>
+"Then one man at a time, and the short men first."
+</para>
+
+<para>
+The Centipede was the first to be pulled aboard, and he came
+willingly, though he objected when the constable put the handcuffs
+on him.  Barchi was next hauled in, quite meek and resigned from
+his soaking.  When we had ten in, our boat we drew back, and the
+second Whitehall was loaded.  The third Whitehall received nine
+prisoners only - a catch of twenty-nine in all.
+</para>
+
+<para>
+"You didn't get the Porpoise," the Centipede said exultantly, as
+though his escape materially diminished our success.
+</para>
+
+<para>
+Charley laughed.  "But we saw him just the same, a-snorting for
+shore like a puffing pig."
+</para>
+
+<para>
+It was a mild and shivering band of pirates that we marched up the
+beach to the oyster house.  In answer to Charley's knock, the door
+was flung open, and a pleasant wave of warm air rushed out upon us.
+</para>
+
+<para>
+"You can dry your clothes here, lads, and get some hot coffee,"
+Charley announced, as they filed in.
+</para>
+
+<para>
+And there, sitting ruefully by the fire, with a steaming mug in his
+hand, was the Porpoise.  With one accord Nicholas and I looked at
+Charley.  He laughed gleefully.
+</para>
+
+<para>
+"That comes of imagination," he said.  "When you see a thing,
+you've got to see it all around, or what's the good of seeing it at
+all?  I saw the beach, so I left a couple of constables behind to
+keep an eye on it.  That's all."
+</para>
+
+
+</chapter>
+
+<chapter>
+<title>THE SIEGE OF THE "LANCASHIRE QUEEN"</title>
+
+
+<para>
+Possibly our most exasperating experience on the fish patrol was
+when Charley Le Grant and I laid a two weeks' siege to a big four-
+masted English ship.  Before we had finished with the affair, it
+became a pretty mathematical problem, and it was by the merest
+chance that we came into possession of the instrument that brought
+it to a successful termination.
+</para>
+
+<para>
+After our raid on the oyster pirates we had returned to Oakland,
+where two more weeks passed before Neil Partington's wife was out
+of danger and on the highroad to recovery.  So it was after an
+absence of a month, all told, that we turned the Reindeer's nose
+toward Benicia.  When the cat's away the mice will play, and in
+these four weeks the fishermen had become very bold in violating
+the law.  When we passed Point Pedro we noticed many signs of
+activity among the shrimp-catchers, and, well into San Pablo Bay,
+we observed a widely scattered fleet of Upper Bay fishing-boats
+hastily pulling in their nets and getting up sail.
+</para>
+
+<para>
+This was suspicious enough to warrant investigation, and the first
+and only boat we succeeded in boarding proved to have an illegal
+net.  The law permitted no smaller mesh for catching shad than one
+that measured seven and one-half inches inside the knots, while the
+mesh of this particular net measured only three inches.  It was a
+flagrant breach of the rules, and the two fishermen were forthwith
+put under arrest.  Neil Partington took one of them with him to
+help manage the Reindeer, while Charley and I went on ahead with
+the other in the captured boat.
+</para>
+
+<para>
+But the shad fleet had headed over toward the Petaluma shore in
+wild flight, and for the rest of the run through San Pablo Bay we
+saw no more fishermen at all.  Our prisoner, a bronzed and bearded
+Greek, sat sullenly on his net while we sailed his craft.  It was a
+new Columbia River salmon boat, evidently on its first trip, and it
+handled splendidly.  Even when Charley praised it, our prisoner
+refused to speak or to notice us, and we soon gave him up as a most
+unsociable fellow.
+</para>
+
+<para>
+We ran up the Carquinez Straits and edged into the bight at
+Turner's Shipyard for smoother water.  Here were lying several
+English steel sailing ships, waiting for the wheat harvest; and
+here, most unexpectedly, in the precise place where we had captured
+Big Alec, we came upon two Italians in a skiff that was loaded with
+a complete "Chinese" sturgeon line.  The surprise was mutual, and
+we were on top of them before either they or we were aware.
+Charley had barely time to luff into the wind and run up to them.
+I ran forward and tossed them a line with orders to make it fast.
+One of the Italians took a turn with it over a cleat, while I
+hastened to lower our big spritsail.  This accomplished, the salmon
+boat dropped astern, dragging heavily on the skiff.
+</para>
+
+<para>
+Charley came forward to board the prize, but when I proceeded to
+haul alongside by means of the line, the Italians cast it off.  We
+at once began drifting to leeward, while they got out two pairs of
+oars and rowed their light craft directly into the wind.  This
+manoeuvre for the moment disconcerted us, for in our large and
+heavily loaded boat we could not hope to catch them with the oars.
+But our prisoner came unexpectedly to our aid.  His black eyes were
+flashing eagerly, and his face was flushed with suppressed
+excitement, as he dropped the centre-board, sprang forward with a
+single leap, and put up the sail.
+</para>
+
+<para>
+"I've always heard that Greeks don't like Italians," Charley
+laughed, as he ran aft to the tiller.
+</para>
+
+<para>
+And never in my experience have I seen a man so anxious for the
+capture of another as was our prisoner in the chase that followed.
+His eyes fairly snapped, and his nostrils quivered and dilated in a
+most extraordinary way.  Charley steered while he tended the sheet;
+and though Charley was as quick and alert as a cat, the Greek could
+hardly control his impatience.
+</para>
+
+<para>
+The Italians were cut off from the shore, which was fully a mile
+away at its nearest point.  Did they attempt to make it, we could
+haul after them with the wind abeam, and overtake them before they
+had covered an eighth of the distance.  But they were too wise to
+attempt it, contenting themselves with rowing lustily to windward
+along the starboard side of a big ship, the Lancashire Queen.  But
+beyond the ship lay an open stretch of fully two miles to the shore
+in that direction.  This, also, they dared not attempt, for we were
+bound to catch them before they could cover it.  So, when they
+reached the bow of the Lancashire Queen, nothing remained but to
+pass around and row down her port side toward the stern, which
+meant rowing to leeward and giving us the advantage.
+</para>
+
+<para>
+We in the salmon boat, sailing close on the wind, tacked about and
+crossed the ship's bow.  Then Charley put up the tiller and headed
+down the port side of the ship, the Greek letting out the sheet and
+grinning with delight.  The Italians were already half-way down the
+ship's length; but the stiff breeze at our back drove us after them
+far faster than they could row.  Closer and closer we came, and I,
+lying down forward, was just reaching out to grasp the skiff, when
+it ducked under the great stern of the Lancashire Queen.
+</para>
+
+<para>
+The chase was virtually where it had begun.  The Italians were
+rowing up the starboard side of the ship, and we were hauled close
+on the wind and slowly edging out from the ship as we worked to
+windward.  Then they darted around her bow and began the row down
+her port side, and we tacked about, crossed her bow, and went
+plunging down the wind hot after them.  And again, just as I was
+reaching for the skiff, it ducked under the ship's stern and out of
+danger.  And so it went, around and around, the skiff each time
+just barely ducking into safety.
+</para>
+
+<para>
+By this time the ship's crew had become aware of what was taking
+place, and we could see their heads in a long row as they looked at
+us over the bulwarks.  Each time we missed the skiff at the stern,
+they set up a wild cheer and dashed across to the other side of the
+Lancashire Queen to see the chase to wind-ward.  They showered us
+and the Italians with jokes and advice, and made our Greek so angry
+that at least once on each circuit he raised his fist and shook it
+at them in a rage.  They came to look for this, and at each display
+greeted it with uproarious mirth.
+</para>
+
+<para>
+"Wot a circus!" cried one.
+</para>
+
+<para>
+"Tork about yer marine hippodromes, - if this ain't one, I'd like
+to know!" affirmed another.
+</para>
+
+<para>
+"Six-days-go-as-yer-please," announced a third.  "Who says the
+dagoes won't win?"
+</para>
+
+<para>
+On the next tack to windward the Greek offered to change places
+with Charley.
+</para>
+
+<para>
+"Let-a me sail-a de boat," he demanded.  "I fix-a them, I catch-a
+them, sure."
+</para>
+
+<para>
+This was a stroke at Charley's professional pride, for pride
+himself he did upon his boat-sailing abilities; but he yielded the
+tiller to the prisoner and took his place at the sheet.  Three
+times again we made the circuit, and the Greek found that he could
+get no more speed out of the salmon boat than Charley had.
+</para>
+
+<para>
+"Better give it up," one of the sailors advised from above.
+</para>
+
+<para>
+The Greek scowled ferociously and shook his fist in his customary
+fashion.  In the meanwhile my mind had not been idle, and I had
+finally evolved an idea.
+</para>
+
+<para>
+"Keep going, Charley, one time more," I said.
+</para>
+
+<para>
+And as we laid out on the next tack to wind-ward, I bent a piece of
+line to a small grappling hook I had seen lying in the bail-hole.
+The end of the line I made fast to the ring-bolt in the bow, and
+with the hook out of sight I waited for the next opportunity to use
+it.  Once more they made their leeward pull down the port side of
+the Lancashire Queen, and once more we churned down after them
+before the wind.  Nearer and nearer we drew, and I was making
+believe to reach for them as before.  The stern of the skiff was
+not six feet away, and they were laughing at me derisively as they
+ducked under the ship's stern.  At that instant I suddenly arose
+and threw the grappling iron.  It caught fairly and squarely on the
+rail of the skiff, which was jerked backward out of safety as the
+rope tautened and the salmon boat ploughed on.
+</para>
+
+<para>
+A groan went up from the row of sailors above, which quickly
+changed to a cheer as one of the Italians whipped out a long
+sheath-knife and cut the rope.  But we had drawn them out of
+safety, and Charley, from his place in the stern-sheets, reached
+over and clutched the stern of the skiff.  The whole thing happened
+in a second of time, for the first Italian was cutting the rope and
+Charley was clutching the skiff when the second Italian dealt him a
+rap over the head with an oar, Charley released his hold and
+collapsed, stunned, into the bottom of the salmon boat, and the
+Italians bent to their oars and escaped back under the ship's
+stern.
+</para>
+
+<para>
+The Greek took both tiller and sheet and continued the chase around
+the Lancashire Queen, while I attended to Charley, on whose head a
+nasty lump was rapidly rising.  Our sailor audience was wild with
+delight, and to a man encouraged the fleeing Italians.  Charley sat
+up, with one hand on his head, and gazed about him sheepishly.
+</para>
+
+<para>
+"It will never do to let them escape now," he said, at the same
+time drawing his revolver.
+</para>
+
+<para>
+On our next circuit, he threatened the Italians with the weapon;
+but they rowed on stolidly, keeping splendid stroke and utterly
+disregarding him.
+</para>
+
+<para>
+"If you don't stop, I'll shoot," Charley said menacingly.
+</para>
+
+<para>
+But this had no effect, nor were they to be frightened into
+surrendering even when he fired several shots dangerously close to
+them.  It was too much to expect him to shoot unarmed men, and this
+they knew as well as we did; so they continued to pull doggedly
+round and round the ship.
+</para>
+
+<para>
+"We'll run them down, then!" Charley exclaimed.  "We'll wear them
+out and wind them!"
+</para>
+
+<para>
+So the chase continued.  Twenty times more we ran them around the
+Lancashire Queen, and at last we could see that even their iron
+muscles were giving out.  They were nearly exhausted, and it was
+only a matter of a few more circuits, when the game took on a new
+feature.  On the row to windward they always gained on us, so that
+they were half-way down the ship's side on the row to leeward when
+we were passing the bow.  But this last time, as we passed the bow,
+we saw them escaping up the ship's gangway, which had been suddenly
+lowered.  It was an organized move on the part of the sailors,
+evidently countenanced by the captain; for by the time we arrived
+where the gangway had been, it was being hoisted up, and the skiff,
+slung in the ship's davits, was likewise flying aloft out of reach.
+</para>
+
+<para>
+The parley that followed with the captain was short and snappy.  He
+absolutely forbade us to board the Lancashire Queen, and as
+absolutely refused to give up the two men.  By this time Charley
+was as enraged as the Greek.  Not only had he been foiled in a long
+and ridiculous chase, but he had been knocked senseless into the
+bottom of his boat by the men who had escaped him.
+</para>
+
+<para>
+"Knock off my head with little apples," he declared emphatically,
+striking the fist of one hand into the palm of the other, "if those
+two men ever escape me!  I'll stay here to get them if it takes the
+rest of my natural life, and if I don't get them, then I promise
+you I'll live unnaturally long or until I do get them, or my name's
+not Charley Le Grant!"
+</para>
+
+<para>
+And then began the siege of the Lancashire Queen, a siege memorable
+in the annals of both fishermen and fish patrol.  When the Reindeer
+came along, after a fruitless pursuit of the shad fleet, Charley
+instructed Neil Partington to send out his own salmon boat, with
+blankets, provisions, and a fisherman's charcoal stove.  By sunset
+this exchange of boats was made, and we said good-by to our Greek,
+who perforce had to go into Benicia and be locked up for his own
+violation of the law.  After supper, Charley and I kept alternate
+four-hour watches till day-light.  The fishermen made no attempt to
+escape that night, though the ship sent out a boat for scouting
+purposes to find if the coast were clear.
+</para>
+
+<para>
+By the next day we saw that a steady siege was in order, and we
+perfected our plans with an eye to our own comfort.  A dock, known
+as the Solano Wharf, which ran out from the Benicia shore, helped
+us in this.  It happened that the Lancashire Queen, the shore at
+Turner's Shipyard, and the Solano Wharf were the corners of a big
+equilateral triangle.  From ship to shore, the side of the triangle
+along which the Italians had to escape, was a distance equal to
+that from the Solano Wharf to the shore, the side of the triangle
+along which we had to travel to get to the shore before the
+Italians.  But as we could sail much faster than they could row, we
+could permit them to travel about half their side of the triangle
+before we darted out along our side.  If we allowed them to get
+more than half-way, they were certain to beat us to shore; while if
+we started before they were half-way, they were equally certain to
+beat us back to the ship.
+</para>
+
+<para>
+We found that an imaginary line, drawn from the end of the wharf to
+a windmill farther along the shore, cut precisely in half the line
+of the triangle along which the Italians must escape to reach the
+land.  This line made it easy for us to determine how far to let
+them run away before we bestirred ourselves in pursuit.  Day after
+day we would watch them through our glasses as they rowed leisurely
+along toward the half-way point; and as they drew close into line
+with the windmill, we would leap into the boat and get up sail.  At
+sight of our preparation, they would turn and row slowly back to
+the Lancashire Queen, secure in the knowledge that we could not
+overtake them.
+</para>
+
+<para>
+To guard against calms - when our salmon boat would be useless - we
+also had in readiness a light rowing skiff equipped with spoon-
+oars.  But at such times, when the wind failed us, we were forced
+to row out from the wharf as soon as they rowed from the ship.  In
+the night-time, on the other hand, we were compelled to patrol the
+immediate vicinity of the ship; which we did, Charley and I
+standing four-hour watches turn and turn about.  The Italians,
+however, preferred the daytime in which to escape, and so our long
+night vigils were without result.
+</para>
+
+<para>
+"What makes me mad," said Charley, "is our being kept from our
+honest beds while those rascally lawbreakers are sleeping soundly
+every night.  But much good may it do them," he threatened.  "I'll
+keep them on that ship till the captain charges them board, as sure
+as a sturgeon's not a catfish!"
+</para>
+
+<para>
+It was a tantalizing problem that confronted us.  As long as we
+were vigilant, they could not escape; and as long as they were
+careful, we would be unable to catch them.  Charley cudgelled his
+brains continually, but for once his imagination failed him.  It
+was a problem apparently without other solution than that of
+patience.  It was a waiting game, and whichever waited the longer
+was bound to win.  To add to our irritation, friends of the
+Italians established a code of signals with them from the shore, so
+that we never dared relax the siege for a moment.  And besides
+this, there were always one or two suspicious-looking fishermen
+hanging around the Solano Wharf and keeping watch on our actions.
+We could do nothing but "grin and bear it," as Charley said, while
+it took up all our time and prevented us from doing other work.
+</para>
+
+<para>
+The days went by, and there was no change in the situation.  Not
+that no attempts were made to change it.  One night friends from
+the shore came out in a skiff and attempted to confuse us while the
+two Italians escaped.  That they did not succeed was due to the
+lack of a little oil on the ship's davits.  For we were drawn back
+from the pursuit of the strange boat by the creaking of the davits,
+and arrived at the Lancashire Queen just as the Italians were
+lowering their skiff.  Another night, fully half a dozen skiffs
+rowed around us in the darkness, but we held on like a leech to the
+side of the ship and frustrated their plan till they grew angry and
+showered us with abuse.  Charley laughed to himself in the bottom
+of the boat.
+</para>
+
+<para>
+"It's a good sign, lad," he said to me.  "When men begin to abuse,
+make sure they're losing patience; and shortly after they lose
+patience, they lose their heads.  Mark my words, if we only hold
+out, they'll get careless some fine day, and then we'll get them."
+</para>
+
+<para>
+But they did not grow careless, and Charley confessed that this was
+one of the times when all signs failed.  Their patience seemed
+equal to ours, and the second week of the siege dragged
+monotonously along.  Then Charley's lagging imagination quickened
+sufficiently to suggest a ruse.  Peter Boyelen, a new patrolman and
+one unknown to the fisher-folk, happened to arrive in Benicia and
+we took him into our plan.  We were as secret as possible about it,
+but in some unfathomable way the friends ashore got word to the
+beleaguered Italians to keep their eyes open.
+</para>
+
+<para>
+On the night we were to put our ruse into effect, Charley and I
+took up our usual station in our rowing skiff alongside the
+Lancashire Queen.  After it was thoroughly dark, Peter Boyelen came
+out in a crazy duck boat, the kind you can pick up and carry away
+under one arm.  When we heard him coming along, paddling noisily,
+we slipped away a short distance into the darkness, and rested on
+our oars.  Opposite the gangway, having jovially hailed the anchor-
+watch of the Lancashire Queen and asked the direction of the
+Scottish Chiefs, another wheat ship, he awkwardly capsized himself.
+The man who was standing the anchor-watch ran down the gangway and
+hauled him out of the water.  This was what he wanted, to get
+aboard the ship; and the next thing he expected was to be taken on
+deck and then below to warm up and dry out.  But the captain
+inhospitably kept him perched on the lowest gang-way step,
+shivering miserably and with his feet dangling in the water, till
+we, out of very pity, rowed in from the darkness and took him off.
+The jokes and gibes of the awakened crew sounded anything but sweet
+in our ears, and even the two Italians climbed up on the rail and
+laughed down at us long and maliciously.
+</para>
+
+<para>
+"That's all right," Charley said in a low voice, which I only could
+hear.  "I'm mighty glad it's not us that's laughing first.  We'll
+save our laugh to the end, eh, lad?"
+</para>
+
+<para>
+He clapped a hand on my shoulder as he finished, but it seemed to
+me that there was more determination than hope in his voice.
+</para>
+
+<para>
+It would have been possible for us to secure the aid of United
+States marshals and board the English ship, backed by Government
+authority.  But the instructions of the Fish Commission were to the
+effect that the patrolmen should avoid complications, and this one,
+did we call on the higher powers, might well end in a pretty
+international tangle.
+</para>
+
+<para>
+The second week of the siege drew to its close, and there was no
+sign of change in the situation.  On the morning of the fourteenth
+day the change came, and it came in a guise as unexpected and
+startling to us as it was to the men we were striving to capture.
+</para>
+
+<para>
+Charley and I, after our customary night vigil by the side of the
+Lancashire Queen, rowed into the Solana Wharf.
+</para>
+
+<para>
+"Hello!" cried Charley, in surprise.  "In the name of reason and
+common sense, what is that?  Of all unmannerly craft did you ever
+see the like?"
+</para>
+
+<para>
+Well might he exclaim, for there, tied up to the dock, lay the
+strangest looking launch I had ever seen.  Not that it could be
+called a launch, either, but it seemed to resemble a launch more
+than any other kind of boat.  It was seventy feet long, but so
+narrow was it, and so bare of superstructure, that it appeared much
+smaller than it really was.  It was built wholly of steel, and was
+painted black.  Three smokestacks, a good distance apart and raking
+well aft, arose in single file amidships; while the bow, long and
+lean and sharp as a knife, plainly advertised that the boat was
+made for speed.  Passing under the stern, we read Streak, painted
+in small white letters.
+</para>
+
+<para>
+Charley and I were consumed with curiosity.  In a few minutes we
+were on board and talking with an engineer who was watching the
+sunrise from the deck.  He was quite willing to satisfy our
+curiosity, and in a few minutes we learned that the Streak had come
+in after dark from San Francisco; that this was what might be
+called the trial trip; and that she was the property of Silas Tate,
+a young mining millionaire of California, whose fad was high-speed
+yachts.  There was some talk about turbine engines, direct
+application of steam, and the absence of pistons, rods, and cranks,
+- all of which was beyond me, for I was familiar only with sailing
+craft; but I did understand the last words of the engineer.
+</para>
+
+<para>
+"Four thousand horse-power and forty-five miles an hour, though you
+wouldn't think it," he concluded proudly.
+</para>
+
+<para>
+"Say it again, man!  Say it again!" Charley exclaimed in an excited
+voice.
+</para>
+
+<para>
+"Four thousand horse-power and forty-five miles an hour," the
+engineer repeated, grinning good-naturedly.
+</para>
+
+<para>
+"Where's the owner?" was Charley's next question.  "Is there any
+way I can speak to him?"
+</para>
+
+<para>
+The engineer shook his head.  "No, I'm afraid not.  He's asleep,
+you see."
+</para>
+
+<para>
+At that moment a young man in blue uniform came on deck farther aft
+and stood regarding the sunrise.
+</para>
+
+<para>
+"There he is, that's him, that's Mr. Tate," said the engineer.
+</para>
+
+<para>
+Charley walked aft and spoke to him, and while he talked earnestly
+the young man listened with an amused expression on his face.  He
+must have inquired about the depth of water close in to the shore
+at Turner's Shipyard, for I could see Charley making gestures and
+explaining.  A few minutes later he came back in high glee.
+</para>
+
+<para>
+"Come on lad," he said.  "On to the dock with you.  We've got
+them!"
+</para>
+
+<para>
+It was our good fortune to leave the Streak when we did, for a
+little later one of the spy fishermen appeared.  Charley and I took
+up our accustomed places, on the stringer-piece, a little ahead of
+the Streak and over our own boat, where we could comfortably watch
+the Lancashire Queen.  Nothing occurred till about nine o'clock,
+when we saw the two Italians leave the ship and pull along their
+side of the triangle toward the shore.  Charley looked as
+unconcerned as could be, but before they had covered a quarter of
+the distance, he whispered to me:
+</para>
+
+<para>
+"Forty-five miles an hour . . . nothing can save them . . . they
+are ours!"
+</para>
+
+<para>
+Slowly the two men rowed along till they were nearly in line with
+the windmill.  This was the point where we always jumped into our
+salmon boat and got up the sail, and the two men, evidently
+expecting it, seemed surprised when we gave no sign.
+</para>
+
+<para>
+When they were directly in line with the windmill, as near to the
+shore as to the ship, and nearer the shore than we had ever allowed
+them before, they grew suspicious.  We followed them through the
+glasses, and saw them standing up in the skiff and trying to find
+out what we were doing.  The spy fisherman, sitting beside us on
+the stringer-piece was likewise puzzled.  He could not understand
+our inactivity.  The men in the skiff rowed nearer the shore, but
+stood up again and scanned it, as if they thought we might be in
+hiding there.  But a man came out on the beach and waved a
+handkerchief to indicate that the coast was clear.  That settled
+them.  They bent to the oars to make a dash for it.  Still Charley
+waited.  Not until they had covered three-quarters of the distance
+from the Lancashire Queen, which left them hardly more than a
+quarter of a mile to gain the shore, did Charley slap me on the
+shoulder and cry:
+</para>
+
+<para>
+"They're ours!  They're ours!"
+</para>
+
+<para>
+We ran the few steps to the side of the Streak and jumped aboard.
+Stern and bow lines were cast off in a jiffy.  The Streak shot
+ahead and away from the wharf.  The spy fisherman we had left
+behind on the stringer-piece pulled out a revolver and fired five
+shots into the air in rapid succession.  The men in the skiff gave
+instant heed to the warning, for we could see them pulling away
+like mad.
+</para>
+
+<para>
+But if they pulled like mad, I wonder how our progress can be
+described?  We fairly flew.  So frightful was the speed with which
+we displaced the water, that a wave rose up on either side our bow
+and foamed aft in a series of three stiff, up-standing waves, while
+astern a great crested billow pursued us hungrily, as though at
+each moment it would fall aboard and destroy us.  The Streak was
+pulsing and vibrating and roaring like a thing alive.  The wind of
+our progress was like a gale - a forty-five-mile gale.  We could
+not face it and draw breath without choking and strangling.  It
+blew the smoke straight back from the mouths of the smoke-stacks at
+a direct right angle to the perpendicular.  In fact, we were
+travelling as fast as an express train.  "We just streaked it," was
+the way Charley told it afterward, and I think his description
+comes nearer than any I can give.
+</para>
+
+<para>
+As for the Italians in the skiff - hardly had we started, it seemed
+to me, when we were on top of them.  Naturally, we had to slow down
+long before we got to them; but even then we shot past like a
+whirlwind and were compelled to circle back between them and the
+shore.  They had rowed steadily, rising from the thwarts at every
+stroke, up to the moment we passed them, when they recognized
+Charley and me.  That took the last bit of fight out of them.  They
+hauled in their oars, and sullenly submitted to arrest.
+</para>
+
+<para>
+"Well, Charley," Neil Partington said, as we discussed it on the
+wharf afterward, "I fail to see where your boasted imagination came
+into play this time."
+</para>
+
+<para>
+But Charley was true to his hobby.  "Imagination?" he demanded,
+pointing to the Streak.  "Look at that! just look at it!  If the
+invention of that isn't imagination, I should like to know what
+is."
+</para>
+
+<para>
+"Of course," he added, "it's the other fellow's imagination, but it
+did the work all the same."
+</para>
+
+
+</chapter>
+
+<chapter>
+<title>CHARLEY'S COUP</title>
+
+
+<para>
+Perhaps our most laughable exploit on the fish patrol, and at the
+same time our most dangerous one, was when we rounded in, at a
+single haul, an even score of wrathful fishermen.  Charley called
+it a "coop," having heard Neil Partington use the term; but I think
+he misunderstood the word, and thought it meant "coop," to catch,
+to trap.  The fishermen, however, coup or coop, must have called it
+a Waterloo, for it was the severest stroke ever dealt them by the
+fish patrol, while they had invited it by open and impudent
+defiance of the law.
+</para>
+
+<para>
+During what is called the "open season" the fishermen might catch
+as many salmon as their luck allowed and their boats could hold.
+But there was one important restriction.  From sun-down Saturday
+night to sun-up Monday morning, they were not permitted to set a
+net.  This was a wise provision on the part of the Fish Commission,
+for it was necessary to give the spawning salmon some opportunity
+to ascend the river and lay their eggs.  And this law, with only an
+occasional violation, had been obediently observed by the Greek
+fishermen who caught salmon for the canneries and the market.
+</para>
+
+<para>
+One Sunday morning, Charley received a telephone call from a friend
+in Collinsville, who told him that the full force of fishermen was
+out with its nets.  Charley and I jumped into our salmon boat and
+started for the scene of the trouble.  With a light favoring wind
+at our back we went through the Carquinez Straits, crossed Suisun
+Bay, passed the Ship Island Light, and came upon the whole fleet at
+work.
+</para>
+
+<para>
+But first let me describe the method by which they worked.  The net
+used is what is known as a gill-net.  It has a simple diamond-
+shaped mesh which measures at least seven and one-half inches
+between the knots.  From five to seven and even eight hundred feet
+in length, these nets are only a few feet wide.  They are not
+stationary, but float with the current, the upper edge supported on
+the surface by floats, the lower edge sunk by means of leaden
+weights,
+</para>
+
+<para>
+This arrangement keeps the net upright in the current and
+effectually prevents all but the smaller fish from ascending the
+river.  The salmon, swimming near the surface, as is their custom,
+run their heads through these meshes, and are prevented from going
+on through by their larger girth of body, and from going back
+because of their gills, which catch in the mesh.  It requires two
+fishermen to set such a net, - one to row the boat, while the
+other, standing in the stern, carefully pays out the net.  When it
+is all out, stretching directly across the stream, the men make
+their boat fast to one end of the net and drift along with it.
+</para>
+
+<para>
+As we came upon the fleet of law-breaking fishermen, each boat two
+or three hundred yards from its neighbors, and boats and nets
+dotting the river as far as we could see, Charley said:
+</para>
+
+<para>
+"I've only one regret, lad, and that is that I have'nt a thousand
+arms so as to be able to catch them all.  As it is, we'll only be
+able to catch one boat, for while we are tackling that one it will
+be up nets and away with the rest."
+</para>
+
+<para>
+As we drew closer, we observed none of the usual flurry and
+excitement which our appearance invariably produced.  Instead, each
+boat lay quietly by its net, while the fishermen favored us with
+not the slightest attention.
+</para>
+
+<para>
+"It's curious," Charley muttered.  "Can it be they don't recognize
+us?"
+</para>
+
+<para>
+I said that it was impossible, and Charley agreed; yet there was a
+whole fleet, manned by men who knew us only too well, and who took
+no more notice of us than if we were a hay scow or a pleasure
+yacht.
+</para>
+
+<para>
+This did not continue to be the case, however, for as we bore down
+upon the nearest net, the men to whom it belonged detached their
+boat and rowed slowly toward the shore.  The rest of the boats
+showed no, sign of uneasiness.
+</para>
+
+<para>
+"That's funny," was Charley's remark.  "But we can confiscate the
+net, at any rate."
+</para>
+
+<para>
+We lowered sail, picked up one end of the net, and began to heave
+it into the boat.  But at the first heave we heard a bullet zip-
+zipping past us on the water, followed by the faint report of a
+rifle.  The men who had rowed ashore were shooting at us.  At the
+next heave a second bullet went zipping past, perilously near.
+Charley took a turn around a pin and sat down.  There were no more
+shots.  But as soon as he began to heave in, the shooting
+recommenced.
+</para>
+
+<para>
+"That settles it," he said, flinging the end of the net overboard.
+"You fellows want it worse than we do, and you can have it."
+</para>
+
+<para>
+We rowed over toward the next net, for Charley was intent on
+finding out whether or not we were face to face with an organized
+defiance.  As we approached, the two fishermen proceeded to cast
+off from their net and row ashore, while the first two rowed back
+and made fast to the net we had abandoned.  And at the second net
+we were greeted by rifle shots till we desisted and went on to the
+third, where the manoeuvre was again repeated.
+</para>
+
+<para>
+Then we gave it up, completely routed, and hoisted sail and started
+on the long windward beat back to Benicia.  A number of Sundays
+went by, on each of which the law was persistently violated.  Yet,
+short of an armed force of soldiers, we could do nothing.  The
+fishermen had hit upon a new idea and were using it for all it was
+worth, while there seemed no way by which we could get the better
+of them.
+</para>
+
+<para>
+About this time Neil Partington happened along from the Lower Bay,
+where he had been for a number of weeks.  With him was Nicholas,
+the Greek boy who had helped us in our raid on the oyster pirates,
+and the pair of them took a hand.  We made our arrangements
+carefully.  It was planned that while Charley and I tackled the
+nets, they were to be hidden ashore so as to ambush the fishermen
+who landed to shoot at us.
+</para>
+
+<para>
+It was a pretty plan.  Even Charley said it was.  But we reckoned
+not half so well as the Greeks.  They forestalled us by ambushing
+Neil and Nicholas and taking them prisoners, while, as of old,
+bullets whistled about our ears when Charley and I attempted to
+take possession of the nets.  When we were again beaten off, Neil
+Partington and Nicholas were released.  They were rather shamefaced
+when they put in an appearance, and Charley chaffed them
+unmercifully.  But Neil chaffed back, demanding to know why
+Charley's imagination had not long since overcome the difficulty.
+</para>
+
+<para>
+"Just you wait; the idea'll come all right," Charley promised.
+</para>
+
+<para>
+"Most probably," Neil agreed.  "But I'm afraid the salmon will be
+exterminated first, and then there will be no need for it when it
+does come."
+</para>
+
+<para>
+Neil Partington, highly disgusted with his adventure, departed for
+the Lower Bay, taking Nicholas with him, and Charley and I were
+left to our own resources.  This meant that the Sunday fishing
+would be left to itself, too, until such time as Charley's idea
+happened along.  I puzzled my head a good deal to find out some way
+of checkmating the Greeks, as also did Charley, and we broached a
+thousand expedients which on discussion proved worthless.
+</para>
+
+<para>
+The fishermen, on the other hand, were in high feather, and their
+boasts went up and down the river to add to our discomfiture.
+Among all classes of them we became aware of a growing
+insubordination.  We were beaten, and they were losing respect for
+us.  With the loss of respect, contempt began to arise.  Charley
+began to be spoken of as the "olda woman," and I received my rating
+as the "pee-wee kid."  The situation was fast becoming unbearable,
+and we knew that we should have to deliver a stunning stroke at the
+Greeks in order to regain the old-time respect in which we had
+stood.
+</para>
+
+<para>
+Then one morning the idea came.  We were down on Steamboat Wharf,
+where the river steamers made their landings, and where we found a
+group of amused long-shoremen and loafers listening to the hard-
+luck tale of a sleepy-eyed young fellow in long sea-boots.  He was
+a sort of amateur fisherman, he said, fishing for the local market
+of Berkeley.  Now Berkeley was on the Lower Bay, thirty miles away.
+On the previous night, he said, he had set his net and dozed off to
+sleep in the bottom of the boat.
+</para>
+
+<para>
+The next he knew it was morning, and he opened his eyes to find his
+boat rubbing softly against the piles of Steamboat Wharf at
+Benicia.  Also he saw the river steamer Apache lying ahead of him,
+and a couple of deck-hands disentangling the shreds of his net from
+the paddle-wheel.  In short, after he had gone to sleep, his
+fisherman's riding light had gone out, and the Apache had run over
+his net.  Though torn pretty well to pieces, the net in some way
+still remained foul, and he had had a thirty-mile tow out of his
+course.
+</para>
+
+<para>
+Charley nudged me with his elbow.  I grasped his thought on the
+instant, but objected:
+</para>
+
+<para>
+"We can't charter a steamboat."
+</para>
+
+<para>
+"Don't intend to," he rejoined.  "But let's run over to Turner's
+Shipyard.  I've something in my mind there that may be of use to
+us."
+</para>
+
+<para>
+And over we went to the shipyard, where Charley led the way to the
+Mary Rebecca, lying hauled out on the ways, where she was being
+cleaned and overhauled.  She was a scow-schooner we both knew well,
+carrying a cargo of one hundred and forty tons and a spread of
+canvas greater than other schooner on the bay.
+</para>
+
+<para>
+"How d'ye do, Ole," Charley greeted a big blue-shirted Swede who
+was greasing the jaws of the main gaff with a piece of pork rind.
+</para>
+
+<para>
+Ole grunted, puffed away at his pipe, and went on greasing.  The
+captain of a bay schooner is supposed to work with his hands just
+as well as the men.
+</para>
+
+<para>
+Ole Ericsen verified Charley's conjecture that the Mary Rebecca, as
+soon as launched, would run up the San Joaquin River nearly to
+Stockton for a load of wheat.  Then Charley made his proposition,
+and Ole Ericsen shook his head.
+</para>
+
+<para>
+"Just a hook, one good-sized hook," Charley pleaded.
+</para>
+
+<para>
+"No, Ay tank not," said Ole Ericsen.  "Der Mary Rebecca yust hang
+up on efery mud-bank with that hook.  Ay don't want to lose der
+Mary Rebecca.  She's all Ay got."
+</para>
+
+<para>
+"No, no," Charley hurried to explain.  "We can put the end of the
+hook through the bottom from the outside, and fasten it on the
+inside with a nut.  After it's done its work, why, all we have to
+do is to go down into the hold, unscrew the nut, and out drops the
+hook.  Then drive a wooden peg into the hole, and the Mary Rebecca
+will be all right again."
+</para>
+
+<para>
+Ole Ericsen was obstinate for a long time; but in the end, after we
+had had dinner with him, he was brought round to consent.
+</para>
+
+<para>
+"Ay do it, by Yupiter!" he said, striking one huge fist into the
+palm of the other hand.  "But yust hurry you up wid der hook.  Der
+Mary Rebecca slides into der water to-night."
+</para>
+
+<para>
+It was Saturday, and Charley had need to hurry.  We headed for the
+shipyard blacksmith shop, where, under Charley's directions, a most
+generously curved book of heavy steel was made.  Back we hastened
+to the Mary Rebecca.  Aft of the great centre-board case, through
+what was properly her keel, a hole was bored.  The end of the hook
+was inserted from the outside, and Charley, on the inside, screwed
+the nut on tightly.  As it stood complete, the hook projected over
+a foot beneath the bottom of the schooner.  Its curve was something
+like the curve of a sickle, but deeper.
+</para>
+
+<para>
+In the late afternoon the Mary Rebecca was launched, and
+preparations were finished for the start up-river next morning.
+Charley and Ole intently studied the evening sky for signs of wind,
+for without a good breeze our project was doomed to failure.  They
+agreed that there were all the signs of a stiff westerly wind - not
+the ordinary afternoon sea-breeze, but a half-gale, which even then
+was springing up.
+</para>
+
+<para>
+Next morning found their predictions verified.  The sun was shining
+brightly, but something more than a half-gale was shrieking up the
+Carquinez Straits, and the Mary Rebecca got under way with two
+reefs in her mainsail and one in her foresail.  We found it quite
+rough in the Straits and in Suisun Bay; but as the water grew more
+land-locked it became calm, though without let-up in the wind.
+</para>
+
+<para>
+Off Ship Island Light the reefs were shaken out, and at Charley's
+suggestion a big fisherman's staysail was made all ready for
+hoisting, and the maintopsail, bunched into a cap at the masthead,
+was overhauled so that it could be set on an instant's notice.
+</para>
+
+<para>
+We were tearing along, wing-and-wing, before the wind, foresail to
+starboard and mainsail to port, as we came upon the salmon fleet.
+There they were, boats and nets, as on that first Sunday when they
+had bested us, strung out evenly over the river as far as we could
+see.  A narrow space on the right-hand side of the channel was left
+clear for steamboats, but the rest of the river was covered with
+the wide-stretching nets.  The narrow space was our logical course,
+but Charley, at the wheel, steered the Mary Rebecca straight for
+the nets.  This did not cause any alarm among the fishermen,
+because up-river sailing craft are always provided with "shoes" on
+the ends of their keels, which permit them to slip over the nets
+without fouling them.
+</para>
+
+<para>
+"Now she takes it!" Charley cried, as we dashed across the middle
+of a line of floats which marked a net.  At one end of this line
+was a small barrel buoy, at the other the two fishermen in their
+boat.  Buoy and boat at once began to draw together, and the
+fishermen to cry out, as they were jerked after us.  A couple of
+minutes later we hooked a second net, and then a third, and in this
+fashion we tore straight up through the centre of the fleet.
+</para>
+
+<para>
+The consternation we spread among the fishermen was tremendous.  As
+fast as we hooked a net the two ends of it, buoy and boat, came
+together as they dragged out astern; and so many buoys and boats,
+coming together at such breakneck speed, kept the fishermen on the
+jump to avoid smashing into one another.  Also, they shouted at us
+like mad to heave to into the wind, for they took it as some
+drunken prank on the part of scow-sailors, little dreaming that we
+were the fish patrol.
+</para>
+
+<para>
+The drag of a single net is very heavy, and Charley and Ole Ericsen
+decided that even in such a wind ten nets were all the Mary Rebecca
+could take along with her.  So when we had hooked ten nets, with
+ten boats containing twenty men streaming along behind us, we
+veered to the left out of the fleet and headed toward Collinsville.
+</para>
+
+<para>
+We were all jubilant.  Charley was handling the wheel as though he
+were steering the winning yacht home in a race.  The two sailors
+who made up the crew of the Mary Rebecca, were grinning and joking.
+Ole Ericsen was rubbing his huge hands in child-like glee.
+</para>
+
+<para>
+"Ay tank you fish patrol fallers never ban so lucky as when you
+sail with Ole Ericsen," he was saying, when a rifle cracked sharply
+astern, and a bullet gouged along the newly painted cabin, glanced
+on a nail, and sang shrilly onward into space.
+</para>
+
+<para>
+This was too much for Ole Ericsen.  At sight of his beloved
+paintwork thus defaced, he jumped up and shook his fist at the
+fishermen; but a second bullet smashed into the cabin not six
+inches from his head, and he dropped down to the deck under cover
+of the rail.
+</para>
+
+<para>
+All the fishermen had rifles, and they now opened a general
+fusillade.  We were all driven to cover - even Charley, who was
+compelled to desert the wheel.  Had it not been for the heavy drag
+of the nets, we would inevitably have broached to at the mercy of
+the enraged fishermen.  But the nets, fastened to the bottom of the
+Mary Rebecca well aft, held her stern into the wind, and she
+continued to plough on, though somewhat erratically.
+</para>
+
+<para>
+Charley, lying on the deck, could just manage to reach the lower
+spokes of the wheel; but while he could steer after a fashion, it
+was very awkward.  Ole Ericsen bethought himself of a large piece
+of sheet steel in the empty hold.
+</para>
+
+<para>
+It was in fact a plate from the side of the New Jersey, a steamer
+which had recently been wrecked outside the Golden Gate, and in the
+salving of which the Mary Rebecca had taken part.
+</para>
+
+<para>
+Crawling carefully along the deck, the two sailors, Ole, and myself
+got the heavy plate on deck and aft, where we reared it as a shield
+between the wheel and the fishermen.  The bullets whanged and
+banged against it till it rang like a bull's-eye, but Charley
+grinned in its shelter, and coolly went on steering.
+</para>
+
+<para>
+So we raced along, behind us a howling, screaming bedlam of
+wrathful Greeks, Collinsville ahead, and bullets spat-spatting all
+around us.
+</para>
+
+<para>
+"Ole," Charley said in a faint voice, "I don't know what we're
+going to do."
+</para>
+
+<para>
+Ole Ericsen, lying on his back close to the rail and grinning
+upward at the sky, turned over on his side and looked at him.  "Ay
+tank we go into Collinsville yust der same," he said.
+</para>
+
+<para>
+"But we can't stop," Charley groaned.  "I never thought of it, but
+we can't stop."
+</para>
+
+<para>
+A look of consternation slowly overspread Ole Ericsen's broad face.
+It was only too true.  We had a hornet's nest on our hands, and to
+stop at Collinsville would be to have it about our ears.
+</para>
+
+<para>
+"Every man Jack of them has a gun," one of the sailors remarked
+cheerfully.
+</para>
+
+<para>
+"Yes, and a knife, too," the other sailor added.
+</para>
+
+<para>
+It was Ole Ericsen's turn to groan.  "What for a Svaidish faller
+like me monkey with none of my biziness, I don't know," he
+soliloquized.
+</para>
+
+<para>
+A bullet glanced on the stern and sang off to starboard like a
+spiteful bee.  "There's nothing to do but plump the Mary Rebecca
+ashore and run for it," was the verdict of the first cheerful
+sailor.
+</para>
+
+<para>
+"And leaf der Mary Rebecca?" Ole demanded, with unspeakable horror
+in his voice.
+</para>
+
+<para>
+"Not unless you want to," was the response.  "But I don't want to
+be within a thousand miles of her when those fellers come aboard" -
+indicating the bedlam of excited Greeks towing behind.
+</para>
+
+<para>
+We were right in at Collinsville then, and went foaming by within
+biscuit-toss of the wharf.
+</para>
+
+<para>
+"I only hope the wind holds out," Charley said, stealing a glance
+at our prisoners.
+</para>
+
+<para>
+"What of der wind?" Ole demanded disconsolately.  "Der river will
+not hold out, and then . . . and then . . ."
+</para>
+
+<para>
+"It's head for tall timber, and the Greeks take the hindermost,"
+adjudged the cheerful sailor, while Ole was stuttering over what
+would happen when we came to the end of the river.
+</para>
+
+<para>
+We had now reached a dividing of the ways.  To the left was the
+mouth of the Sacramento River, to the right the mouth of the San
+Joaquin.  The cheerful sailor crept forward and jibed over the
+foresail as Charley put the helm to starboard and we swerved to the
+right into the San Joaquin.  The wind, from which we had been
+running away on an even keel, now caught us on our beam, and the
+Mary Rebecca was pressed down on her port side as if she were about
+to capsize.
+</para>
+
+<para>
+Still we dashed on, and still the fishermen dashed on behind.  The
+value of their nets was greater than the fines they would have to
+pay for violating the fish laws; so to cast off from their nets and
+escape, which they could easily do, would profit them nothing.
+Further, they remained by their nets instinctively, as a sailor
+remains by his ship.  And still further, the desire for vengeance
+was roused, and we could depend upon it that they would follow us
+to the ends of the earth, if we undertook to tow them that far.
+</para>
+
+<para>
+The rifle-firing had ceased, and we looked astern to see what our
+prisoners were doing.  The boats were strung along at unequal
+distances apart, and we saw the four nearest ones bunching
+together.  This was done by the boat ahead trailing a small rope
+astern to the one behind.  When this was caught, they would cast
+off from their net and heave in on the line till they were brought
+up to the boat in front.  So great was the speed at which we were
+travelling, however, that this was very slow work.  Sometimes the
+men would strain to their utmost and fail to get in an inch of the
+rope; at other times they came ahead more rapidly.
+</para>
+
+<para>
+When the four boats were near enough together for a man to pass
+from one to another, one Greek from each of three got into the
+nearest boat to us, taking his rifle with him.  This made five in
+the foremost boat, and it was plain that their intention was to
+board us.  This they undertook to do, by main strength and sweat,
+running hand over hand the float-line of a net.  And though it was
+slow, and they stopped frequently to rest, they gradually drew
+nearer.
+</para>
+
+<para>
+Charley smiled at their efforts, and said, "Give her the topsail,
+Ole."
+</para>
+
+<para>
+The cap at the mainmast head was broken out, and sheet and downhaul
+pulled flat, amid a scattering rifle fire from the boats; and the
+Mary Rebecca lay over and sprang ahead faster than ever.
+</para>
+
+<para>
+But the Greeks were undaunted.  Unable, at the increased speed, to
+draw themselves nearer by means of their hands, they rigged from
+the blocks of their boat sail what sailors call a "watch-tackle."
+One of them, held by the legs by his mates, would lean far over the
+bow and make the tackle fast to the float-line.  Then they would
+heave in on the tackle till the blocks were together, when the
+manoeuvre would be repeated.
+</para>
+
+<para>
+"Have to give her the staysail," Charley said.
+</para>
+
+<para>
+Ole Ericsen looked at the straining Mary Rebecca and shook his
+head.  "It will take der masts out of her," he said.
+</para>
+
+<para>
+"And we'll be taken out of her if you don't," Charley replied.
+</para>
+
+<para>
+Ole shot an anxious glance at his masts, another at the boat load
+of armed Greeks, and consented.
+</para>
+
+<para>
+The five men were in the bow of the boat - a bad place when a craft
+is towing.  I was watching the behavior of their boat as the great
+fisherman's staysail, far, far larger than the top-sail and used
+only in light breezes, was broken out.  As the Mary Rebecca lurched
+forward with a tremendous jerk, the nose of the boat ducked down
+into the water, and the men tumbled over one another in a wild rush
+into the stern to save the boat from being dragged sheer under
+water.
+</para>
+
+<para>
+"That settles them!" Charley remarked, though he was anxiously
+studying the behavior of the Mary Rebecca, which was being driven
+under far more canvas than she was rightly able to carry.
+</para>
+
+<para>
+"Next stop is Antioch!" announced the cheerful sailor, after the
+manner of a railway conductor.  "And next comes Merryweather!"
+</para>
+
+<para>
+"Come here, quick," Charley said to me.
+</para>
+
+<para>
+I crawled across the deck and stood upright beside him in the
+shelter of the sheet steel.
+</para>
+
+<para>
+"Feel in my inside pocket," he commanded, "and get my notebook.
+That's right.  Tear out a blank page and write what I tell you."
+</para>
+
+<para>
+And this is what I wrote:
+</para>
+
+<para>
+
+Telephone to Merryweather, to the sheriff, the constable, or the
+judge.  Tell them we are coming and to turn out the town.  Arm
+everybody.  Have them down on the wharf to meet us or we are gone
+gooses.
+</para>
+
+<para>
+
+Now make it good and fast to that marlin-spike, and stand by to
+toss it ashore."
+</para>
+
+<para>
+I did as he directed.  By then we were close to Antioch.  The wind
+was shouting through our rigging, the Mary Rebecca was half over on
+her side and rushing ahead like an ocean greyhound.  The seafaring
+folk of Antioch had seen us breaking out topsail and staysail, a
+most reckless performance in such weather, and had hurried to the
+wharf-ends in little groups to find out what was the matter.
+</para>
+
+<para>
+Straight down the water front we boomed, Charley edging in till a
+man could almost leap ashore.  When he gave the signal I tossed the
+marlinspike.  It struck the planking of the wharf a resounding
+smash, bounced along fifteen or twenty feet, and was pounced upon
+by the amazed onlookers.
+</para>
+
+<para>
+It all happened in a flash, for the next minute Antioch was behind
+and we were heeling it up the San Joaquin toward Merryweather, six
+miles away.  The river straightened out here into its general
+easterly course, and we squared away before the wind, wing-and-wing
+once more, the foresail bellying out to starboard.
+</para>
+
+<para>
+Ole Ericsen seemed sunk into a state of stolid despair.  Charley
+and the two sailors were looking hopeful, as they had good reason
+to be.  Merryweather was a coal-mining town, and, it being Sunday,
+it was reasonable to expect the men to be in town.  Further, the
+coal-miners had never lost any love for the Greek fishermen, and
+were pretty certain to render us hearty assistance.
+</para>
+
+<para>
+We strained our eyes for a glimpse of the town, and the first sight
+we caught of it gave us immense relief.  The wharves were black
+with men.  As we came closer, we could see them still arriving,
+stringing down the main street, guns in their hands and on the run.
+Charley glanced astern at the fishermen with a look of ownership in
+his eye which till then had been missing.  The Greeks were plainly
+overawed by the display of armed strength and were putting their
+own rifles away.
+</para>
+
+<para>
+We took in topsail and staysail, dropped the main peak, and as we
+got abreast of the principal wharf jibed the mainsail.  The Mary
+Rebecca shot around into the wind, the captive fishermen describing
+a great arc behind her, and forged ahead till she lost way, when
+lines we're flung ashore and she was made fast.  This was
+accomplished under a hurricane of cheers from the delighted miners.
+</para>
+
+<para>
+Ole Ericsen heaved a great sigh.  "Ay never tank Ay see my wife
+never again," he confessed.
+</para>
+
+<para>
+"Why, we were never in any danger," said Charley.
+</para>
+
+<para>
+Ole looked at him incredulously.
+</para>
+
+<para>
+"Sure, I mean it," Charley went on.  "All we had to do, any time,
+was to let go our end - as I am going to do now, so that those
+Greeks can untangle their nets."
+</para>
+
+<para>
+He went below with a monkey-wrench, unscrewed the nut, and let the
+hook drop off.  When the Greeks had hauled their nets into their
+boats and made everything shipshape, a posse of citizens took them
+off our hands and led them away to jail.
+</para>
+
+<para>
+"Ay tank Ay ban a great big fool," said Ole Ericsen.  But he
+changed his mind when the admiring townspeople crowded aboard to
+shake hands with him, and a couple of enterprising newspaper men
+took photographs of the Mary Rebecca and her captain.
+</para>
+
+
+</chapter>
+
+<chapter>
+<title>DEMETRIOS CONTOS</title>
+
+
+<para>
+It must not be thought, from what I have told of the Greek
+fishermen, that they were altogether bad.  Far from it.  But they
+were rough men, gathered together in isolated communities and
+fighting with the elements for a livelihood.  They lived far away
+from the law and its workings, did not understand it, and thought
+it tyranny.  Especially did the fish laws seem tyrannical.  And
+because of this, they looked upon the men of the fish patrol as
+their natural enemies.
+</para>
+
+<para>
+We menaced their lives, or their living, which is the same thing,
+in many ways.  We confiscated illegal traps and nets, the materials
+of which had cost them considerable sums and the making of which
+required weeks of labor.  We prevented them from catching fish at
+many times and seasons, which was equivalent to preventing them
+from making as good a living as they might have made had we not
+been in existence.  And when we captured them, they were brought
+into the courts of law, where heavy cash fines were collected from
+them.  As a result, they hated us vindictively.  As the dog is the
+natural enemy of the cat, the snake of man, so were we of the fish
+patrol the natural enemies of the fishermen.
+</para>
+
+<para>
+But it is to show that they could act generously as well as hate
+bitterly that this story of Demetrios Contos is told.  Demetrios
+Contos lived in Vallejo.  Next to Big Alec, he was the largest,
+bravest, and most influential man among the Greeks.  He had given
+us no trouble, and I doubt if he would ever have clashed with us
+had he not invested in a new salmon boat.  This boat was the cause
+of all the trouble.  He had had it built upon his own model, in
+which the lines of the general salmon boat were somewhat modified.
+</para>
+
+<para>
+To his high elation he found his new boat very fast - in fact,
+faster than any other boat on the bay or rivers.  Forthwith he grew
+proud and boastful:  and, our raid with the Mary Rebecca on the
+Sunday salmon fishers having wrought fear in their hearts, he sent
+a challenge up to Benicia.  One of the local fishermen conveyed it
+to us; it was to the effect that Demetrios Contos would sail up
+from Vallejo on the following Sunday, and in the plain sight of
+Benicia set his net and catch salmon, and that Charley Le Grant,
+patrolman, might come and get him if he could.  Of course Charley
+and I had heard nothing of the new boat.  Our own boat was pretty
+fast, and we were not afraid to have a brush with any other that
+happened along.
+</para>
+
+<para>
+Sunday came.  The challenge had been bruited abroad, and the
+fishermen and seafaring folk of Benicia turned out to a man,
+crowding Steamboat Wharf till it looked like the grand stand at a
+football match.  Charley and I had been sceptical, but the fact of
+the crowd convinced us that there was something in Demetrios
+Contos's dare.
+</para>
+
+<para>
+In the afternoon, when the sea-breeze had picked up in strength,
+his sail hove into view as he bowled along before the wind.  He
+tacked a score of feet from the wharf, waved his hand theatrically,
+like a knight about to enter the lists, received a hearty cheer in
+return, and stood away into the Straits for a couple of hundred
+yards.  Then he lowered sail, and, drifting the boat sidewise by
+means of the wind, proceeded to set his net.  He did not set much
+of it, possibly fifty feet; yet Charley and I were thunderstruck at
+the man's effrontery.  We did not know at the time, but we learned
+afterward, that the net he used was old and worthless.  It could
+catch fish, true; but a catch of any size would have torn it to
+pieces.
+</para>
+
+<para>
+Charley shook his head and said:
+</para>
+
+<para>
+"I confess, it puzzles me.  What if he has out only fifty feet?  He
+could never get it in if we once started for him.  And why does he
+come here anyway, flaunting his law-breaking in our faces?  Right
+in our home town, too."
+</para>
+
+<para>
+Charley's voice took on an aggrieved tone, and he continued for
+some minutes to inveigh against the brazenness of Demetrios Contos.
+</para>
+
+<para>
+In the meantime, the man in question was lolling in the stern of
+his boat and watching the net floats.  When a large fish is meshed
+in a gill-net, the floats by their agitation advertise the fact.
+And they evidently advertised it to Demetrios, for he pulled in
+about a dozen feet of net, and held aloft for a moment, before he
+flung it into the bottom of the boat, a big, glistening salmon.  It
+was greeted by the audience on the wharf with round after round of
+cheers.  This was more than Charley could stand.
+</para>
+
+<para>
+"Come on, lad," he called to me; and we lost no time jumping into
+our salmon boat and getting up sail.
+</para>
+
+<para>
+The crowd shouted warning to Demetrios, and as we darted out from
+the wharf we saw him slash his worthless net clear with a long
+knife.  His sail was all ready to go up, and a moment later it
+fluttered in the sunshine.  He ran aft, drew in the sheet, and
+filled on the long tack toward the Contra Costa Hills.
+</para>
+
+<para>
+By this time we were not more than thirty feet astern.  Charley was
+jubilant.  He knew our boat was fast, and he knew, further, that in
+fine sailing few men were his equals.  He was confident that we
+should surely catch Demetrios, and I shared his confidence.  But
+somehow we did not seem to gain.
+</para>
+
+<para>
+It was a pretty sailing breeze.  We were gliding sleekly through
+the water, but Demetrios was slowly sliding away from us.  And not
+only was he going faster, but he was eating into the wind a
+fraction of a point closer than we.  This was sharply impressed
+upon us when he went about under the Contra Costa Hills and passed
+us on the other tack fully one hundred feet dead to windward.
+</para>
+
+<para>
+"Whew!" Charley exclaimed.  "Either that boat is a daisy, or we've
+got a five-gallon coal-oil can fast to our keel!"
+</para>
+
+<para>
+It certainly looked it one way or the other.  And by the time
+Demetrios made the Sonoma Hills, on the other side of the Straits,
+we were so hopelessly outdistanced that Charley told me to slack
+off the sheet, and we squared away for Benicia.  The fishermen on
+Steamboat Wharf showered us with ridicule when we returned and tied
+up.  Charley and I got out and walked away, feeling rather
+sheepish, for it is a sore stroke to one's pride when he thinks he
+has a good boat and knows how to sail it, and another man comes
+along and beats him.
+</para>
+
+<para>
+Charley mooned over it for a couple of days; then word was brought
+to us, as before, that on the next Sunday Demetrios Contos would
+repeat his performance.  Charley roused himself.  He had our boat
+out of the water, cleaned and repainted its bottom, made a trifling
+alteration about the centre-board, overhauled the running gear, and
+sat up nearly all of Saturday night sewing on a new and much larger
+sail.  So large did he make it, in fact, that additional ballast
+was imperative, and we stowed away nearly five hundred extra pounds
+of old railroad iron in the bottom of the boat.
+</para>
+
+<para>
+Sunday came, and with it came Demetrios Contos, to break the law
+defiantly in open day.  Again we had the afternoon sea-breeze, and
+again Demetrios cut loose some forty or more feet of his rotten
+net, and got up sail and under way under our very noses.  But he
+had anticipated Charley's move, and his own sail peaked higher than
+ever, while a whole extra cloth had been added to the after leech.
+</para>
+
+<para>
+It was nip and tuck across to the Contra Costa Hills, neither of us
+seeming to gain or to lose.  But by the time we had made the return
+tack to the Sonoma Hills, we could see that, while we footed it at
+about equal speed, Demetrios had eaten into the wind the least bit
+more than we.  Yet Charley was sailing our boat as finely and
+delicately as it was possible to sail it, and getting more out of
+it than he ever had before.
+</para>
+
+<para>
+Of course, he could have drawn his revolver and fired at Demetrios;
+but we had long since found it contrary to our natures to shoot at
+a fleeing man guilty of only a petty offence.  Also a sort of tacit
+agreement seemed to have been reached between the patrolmen and the
+fishermen.  If we did not shoot while they ran away, they, in turn,
+did not fight if we once laid hands on them.  Thus Demetrios Contos
+ran away from us, and we did no more than try our best to overtake
+him; and, in turn, if our boat proved faster than his, or was
+sailed better, he would, we knew, make no resistance when we caught
+up with him.
+</para>
+
+<para>
+With our large sails and the healthy breeze romping up the
+Carquinez Straits, we found that our sailing was what is called
+"ticklish."  We had to be constantly on the alert to avoid a
+capsize, and while Charley steered I held the main-sheet in my hand
+with but a single turn round a pin, ready to let go at any moment.
+Demetrios, we could see, sailing his boat alone, had his hands
+full.
+</para>
+
+<para>
+But it was a vain undertaking for us to attempt to catch him.  Out
+of his inner consciousness he had evolved a boat that was better
+than ours.  And though Charley sailed fully as well, if not the
+least bit better, the boat he sailed was not so good as the
+Greek's.
+</para>
+
+<para>
+"Slack away the sheet," Charley commanded; and as our boat fell off
+before the wind, Demetrios's mocking laugh floated down to us.
+</para>
+
+<para>
+Charley shook his head, saying, "It's no use.  Demetrios has the
+better boat.  If he tries his performance again, we must meet it
+with some new scheme."
+</para>
+
+<para>
+This time it was my imagination that came to the rescue.
+</para>
+
+<para>
+"What's the matter," I suggested, on the Wednesday following, "with
+my chasing Demetrios in the boat next Sunday, while you wait for
+him on the wharf at Vallejo when he arrives?"
+</para>
+
+<para>
+Charley considered it a moment and slapped his knee.
+</para>
+
+<para>
+"A good idea!  You're beginning to use that head of yours.  A
+credit to your teacher, I must say."
+</para>
+
+<para>
+"But you mustn't chase him too far," he went on, the next moment,
+"or he'll head out into San Pablo Bay instead of running home to
+Vallejo, and there I'll be, standing lonely on the wharf and
+waiting in vain for him to arrive."
+</para>
+
+<para>
+On Thursday Charley registered an objection to my plan.
+</para>
+
+<para>
+"Everybody'll know I've gone to Vallejo, and you can depend upon it
+that Demetrios will know, too.  I'm afraid we'll have to give up
+the idea."
+</para>
+
+<para>
+This objection was only too valid, and for the rest of the day I
+struggled under my disappointment.  But that night a new way seemed
+to open to me, and in my eagerness I awoke Charley from a sound
+sleep.
+</para>
+
+<para>
+"Well," he grunted, "what's the matter?  House afire?"
+</para>
+
+<para>
+"No," I replied, "but my head is.  Listen to this.  On Sunday you
+and I will be around Benicia up to the very moment Demetrios's sail
+heaves into sight.  This will lull everybody's suspicions.  Then,
+when Demetrios's sail does heave in sight, do you stroll leisurely
+away and up-town.  All the fishermen will think you're beaten and
+that you know you're beaten."
+</para>
+
+<para>
+"So far, so good," Charley commented, while I paused to catch
+breath.
+</para>
+
+<para>
+"And very good indeed," I continued proudly.  "You stroll
+carelessly up-town, but when you're once out of sight you leg it
+for all you're worth for Dan Maloney's.  Take the little mare of
+his, and strike out on the country road for Vallejo.  The road's in
+fine condition, and you can make it in quicker time than Demetrios
+can beat all the way down against the wind."
+</para>
+
+<para>
+"And I'll arrange right away for the mare, first thing in the
+morning," Charley said, accepting the modified plan without
+hesitation.
+</para>
+
+<para>
+"But, I say," he said, a little later, this time waking me out of a
+sound sleep.
+</para>
+
+<para>
+I could hear him chuckling in the dark.
+</para>
+
+<para>
+"I say, lad, isn't it rather a novelty for the fish patrol to be
+taking to horseback?"
+</para>
+
+<para>
+"Imagination," I answered.  "It's what you're always preaching -
+'keep thinking one thought ahead of the other fellow, and you're
+bound to win out.'"
+</para>
+
+<para>
+"He! he!" he chuckled.  "And if one thought ahead, including a
+mare, doesn't take the other fellow's breath away this time, I'm
+not your humble servant, Charley Le Grant."
+</para>
+
+<para>
+"But can you manage the boat alone?" he asked, on Friday.
+"Remember, we've a ripping big sail on her."
+</para>
+
+<para>
+I argued my proficiency so well that he did not refer to the matter
+again till Saturday, when he suggested removing one whole cloth
+from the after leech.  I guess it was the disappointment written on
+my face that made him desist; for I, also, had a pride in my boat-
+sailing abilities, and I was almost wild to get out alone with the
+big sail and go tearing down the Carquinez Straits in the wake of
+the flying Greek.
+</para>
+
+<para>
+As usual, Sunday and Demetrios Contos arrived together.  It had
+become the regular thing for the fishermen to assemble on Steamboat
+Wharf to greet his arrival and to laugh at our discomfiture.  He
+lowered sail a couple of hundred yards out and set his customary
+fifty feet of rotten net.
+</para>
+
+<para>
+"I suppose this nonsense will keep up as long as his old net holds
+out," Charley grumbled, with intention, in the hearing of several
+of the Greeks.
+</para>
+
+<para>
+"Den I give-a heem my old-a net-a," one of them spoke up, promptly
+and maliciously,
+</para>
+
+<para>
+"I don't care," Charley answered.  "I've got some old net myself he
+can have - if he'll come around and ask for it."
+</para>
+
+<para>
+They all laughed at this, for they could afford to be sweet-
+tempered with a man so badly outwitted as Charley was.
+</para>
+
+<para>
+"Well, so long, lad," Charley called to me a moment later.  "I
+think I'll go up-town to Maloney's."
+</para>
+
+<para>
+"Let me take the boat out?" I asked.
+</para>
+
+<para>
+"If you want to," was his answer, as he turned on his heel and
+walked slowly away.
+</para>
+
+<para>
+Demetrios pulled two large salmon out of his net, and I jumped into
+the boat.  The fishermen crowded around in a spirit of fun, and
+when I started to get up sail overwhelmed me with all sorts of
+jocular advice.  They even offered extravagant bets to one another
+that I would surely catch Demetrios, and two of them, styling
+themselves the committee of judges, gravely asked permission to
+come along with me to see how I did it.
+</para>
+
+<para>
+But I was in no hurry.  I waited to give Charley all the time I
+could, and I pretended dissatisfaction with the stretch of the sail
+and slightly shifted the small tackle by which the huge sprit
+forces up the peak.  It was not until I was sure that Charley had
+reached Dan Maloney's and was on the little mare's back, that I
+cast off from the wharf and gave the big sail to the wind.  A stout
+puff filled it and suddenly pressed the lee gunwale down till a
+couple of buckets of water came inboard.  A little thing like this
+will happen to the best small-boat sailors, and yet, though I
+instantly let go the sheet and righted, I was cheered
+sarcastically, as though I had been guilty of a very awkward
+blunder.
+</para>
+
+<para>
+When Demetrios saw only one person in the fish patrol boat, and
+that one a boy, he proceeded to play with me.  Making a short tack
+out, with me not thirty feet behind, he returned, with his sheet a
+little free, to Steamboat Wharf.  And there he made short tacks,
+and turned and twisted and ducked around, to the great delight of
+his sympathetic audience.  I was right behind him all the time, and
+I dared to do whatever he did, even when he squared away before the
+wind and jibed his big sail over - a most dangerous trick with such
+a sail in such a wind.
+</para>
+
+<para>
+He depended upon the brisk sea breeze and the strong ebb-tide,
+which together kicked up a nasty sea, to bring me to grief.  But I
+was on my mettle, and never in all my life did I sail a boat better
+than on that day.  I was keyed up to concert pitch, my brain was
+working smoothly and quickly, my hands never fumbled once, and it
+seemed that I almost divined the thousand little things which a
+small-boat sailor must be taking into consideration every second.
+</para>
+
+<para>
+It was Demetrios who came to grief instead.  Something went wrong
+with his centre-board, so that it jammed in the case and would not
+go all the way down.  In a moment's breathing space, which he had
+gained from me by a clever trick, I saw him working impatiently
+with the centre-board, trying to force it down.  I gave him little
+time, and he was compelled quickly to return to the tiller and
+sheet.
+</para>
+
+<para>
+The centre-board made him anxious.  He gave over playing with me,
+and started on the long beat to Vallejo.  To my joy, on the first
+long tack across, I found that I could eat into the wind just a
+little bit closer than he.  Here was where another man in the boat
+would have been of value to him; for, with me but a few feet
+astern, he did not dare let go the tiller and run amidships to try
+to force down the centre-board.
+</para>
+
+<para>
+Unable to hang on as close in the eye of the wind as formerly, he
+proceeded to slack his sheet a trifle and to ease off a bit, in
+order to outfoot me.  This I permitted him to do till I had worked
+to windward, when I bore down upon him.  As I drew close, he
+feinted at coming about.  This led me to shoot into the wind to
+forestall him.  But it was only a feint, cleverly executed, and he
+held back to his course while I hurried to make up lost ground.
+</para>
+
+<para>
+He was undeniably smarter than I when it came to manoeuvring.  Time
+after time I all but had him, and each time he tricked me and
+escaped.  Besides, the wind was freshening, constantly, and each of
+us had his hands full to avoid capsizing.  As for my boat, it could
+not have been kept afloat but for the extra ballast.  I sat cocked
+over the weather gunwale, tiller in one hand and sheet in the
+other; and the sheet, with a single turn around a pin, I was very
+often forced to let go in the severer puffs.  This allowed the sail
+to spill the wind, which was equivalent to taking off so much
+driving power, and of course I lost ground.  My consolation was
+that Demetrios was as often compelled to do the same thing.
+</para>
+
+<para>
+The strong ebb-tide, racing down the Straits in the teeth of the
+wind, caused an unusually heavy and spiteful sea, which dashed
+aboard continually.  I was dripping wet, and even the sail was wet
+half-way up the after leech.  Once I did succeed in outmanoeuvring
+Demetrios, so that my bow bumped into him amidships.  Here was
+where I should have had another man.  Before I could run forward
+and leap aboard, he shoved the boats apart with an oar, laughing
+mockingly in my face as he did so.
+</para>
+
+<para>
+We were now at the mouth of the Straits, in a bad stretch of water.
+Here the Vallejo Straits and the Carquinez Straits rushed directly
+at each other.  Through the first flowed all the water of Napa
+River and the great tide-lands; through the second flowed all the
+water of Suisun Bay and the Sacramento and San Joaquin rivers.  And
+where such immense bodies of water, flowing swiftly, clashed
+together, a terrible tide-rip was produced.  To make it worse, the
+wind howled up San Pablo Bay for fifteen miles and drove in a
+tremendous sea upon the tide-rip.
+</para>
+
+<para>
+Conflicting currents tore about in all directions, colliding,
+forming whirlpools, sucks, and boils, and shooting up spitefully
+into hollow waves which fell aboard as often from leeward as from
+windward.  And through it all, confused, driven into a madness of
+motion, thundered the great smoking seas from San Pablo Bay.
+</para>
+
+<para>
+I was as wildly excited as the water.  The boat was behaving
+splendidly, leaping and lurching through the welter like a race-
+horse.  I could hardly contain myself with the joy of it.  The huge
+sail, the howling wind, the driving seas, the plunging boat - I, a
+pygmy, a mere speck in the midst of it, was mastering the elemental
+strife, flying through it and over it, triumphant and victorious.
+</para>
+
+<para>
+And just then, as I roared along like a conquering hero, the boat
+received a frightful smash and came instantly to a dead stop.  I
+was flung forward and into the bottom.  As I sprang up I caught a
+fleeting glimpse of a greenish, barnacle-covered object, and knew
+it at once for what it was, that terror of navigation, a sunken
+pile.  No man may guard against such a thing.  Water-logged and
+floating just beneath the surface, it was impossible to sight it in
+the troubled water in time to escape.
+</para>
+
+<para>
+The whole bow of the boat must have been crushed in, for in a few
+seconds the boat was half full.  Then a couple of seas filled it,
+and it sank straight down, dragged to bottom by the heavy ballast.
+So quickly did it all happen that I was entangled in the sail and
+drawn under.  When I fought my way to the surface, suffocating, my
+lungs almost bursting, I could see nothing of the oars.  They must
+have been swept away by the chaotic currents.  I saw Demetrios
+Contos looking back from his boat, and heard the vindictive and
+mocking tones of his voice as he shouted exultantly.  He held
+steadily on his course, leaving me to perish.
+</para>
+
+<para>
+There was nothing to do but to swim for it, which, in that wild
+confusion, was at the best a matter of but a few moments.  Holding
+my breath and working with my hands, I managed to get off my heavy
+sea-boots and my jacket.  Yet there was very little breath I could
+catch to hold, and I swiftly discovered that it was not so much a
+matter of swimming as of breathing.
+</para>
+
+<para>
+I was beaten and buffeted, smashed under by the great San Pablo
+whitecaps, and strangled by the hollow tide-rip waves which flung
+themselves into my eyes, nose, and mouth.  Then the strange sucks
+would grip my legs and drag me under, to spout me up in some fierce
+boiling, where, even as I tried to catch my breath, a great
+whitecap would crash down upon my head.
+</para>
+
+<para>
+It was impossible to survive any length of time.  I was breathing
+more water than air, and drowning all the time.  My senses began to
+leave me, my head to whirl around.  I struggled on, spasmodically,
+instinctively, and was barely half conscious when I felt myself
+caught by the shoulders and hauled over the gunwale of a boat.
+</para>
+
+<para>
+For some time I lay across a seat where I had been flung, face
+downward, and with the water running out of my mouth.  After a
+while, still weak and faint, I turned around to see who was my
+rescuer.  And there, in the stern, sheet in one hand and tiller in
+the other, grinning and nodding good-naturedly, sat Demetrios
+Contos.  He had intended to leave me to drown, - he said so
+afterward, - but his better self had fought the battle, conquered,
+and sent him back to me.
+</para>
+
+<para>
+"You all-a right?" he asked.
+</para>
+
+<para>
+I managed to shape a "yes" on my lips, though I could not yet
+speak.
+</para>
+
+<para>
+"You sail-a de boat verr-a good-a," he said.  "So good-a as a man."
+</para>
+
+<para>
+A compliment from Demetrios Contos was a compliment indeed, and I
+keenly appreciated it, though I could only nod my head in
+acknowledgment.
+</para>
+
+<para>
+We held no more conversation, for I was busy recovering and he was
+busy with the boat.  He ran in to the wharf at Vallejo, made the
+boat fast, and helped me out.  Then it was, as we both stood on the
+wharf, that Charley stepped out from behind a net-rack and put his
+hand on Demetrios Contos's arm.
+</para>
+
+<para>
+"He saved my life, Charley," I protested; "and I don't think he
+ought to be arrested."
+</para>
+
+<para>
+A puzzled expression came into Charley's face, which cleared
+immediately after, in a way it had when he made up his mind.
+</para>
+
+<para>
+"I can't help it, lad," he said kindly.  "I can't go back on my
+duty, and it's plain duty to arrest him.  To-day is Sunday; there
+are two salmon in his boat which he caught to-day.  What else can I
+do?"
+</para>
+
+<para>
+"But he saved my life," I persisted, unable to make any other
+argument.
+</para>
+
+<para>
+Demetrios Contos's face went black with rage when he learned
+Charley's judgment.  He had a sense of being unfairly treated.  The
+better part of his nature had triumphed, he had performed a
+generous act and saved a helpless enemy, and in return the enemy
+was taking him to jail.
+</para>
+
+<para>
+Charley and I were out of sorts with each other when we went back
+to Benicia.  I stood for the spirit of the law and not the letter;
+but by the letter Charley made his stand.  As far as he could see,
+there was nothing else for him to do.  The law said distinctly that
+no salmon should be caught on Sunday.  He was a patrolman, and it
+was his duty to enforce that law.  That was all there was to it.
+He had done his duty, and his conscience was clear.  Nevertheless,
+the whole thing seemed unjust to me, and I felt very sorry for
+Demetrios Contos.
+</para>
+
+<para>
+Two days later we went down to Vallejo to the trial.  I had to go
+along as a witness, and it was the most hateful task that I ever
+performed in my life when I testified on the witness stand to
+seeing Demetrios catch the two salmon Charley had captured him
+with.
+</para>
+
+<para>
+Demetrios had engaged a lawyer, but his case was hopeless.  The
+jury was out only fifteen minutes, and returned a verdict of
+guilty.  The judge sentenced Demetrios to pay a fine of one hundred
+dollars or go to jail for fifty days.
+</para>
+
+<para>
+Charley stepped up to the clerk of the court.  "I want to pay that
+fine," he said, at the same time placing five twenty-dollar gold
+pieces on the desk.  "It - it was the only way out of it, lad," he
+stammered, turning to me.
+</para>
+
+<para>
+The moisture rushed into my eyes as I seized his hand.  "I want to
+pay - " I began.
+</para>
+
+<para>
+"To pay your half?" he interrupted.  "I certainly shall expect you
+to pay it."
+</para>
+
+<para>
+In the meantime Demetrios had been informed by his lawyer that his
+fee likewise had been paid by Charley.
+</para>
+
+<para>
+Demetrios came over to shake Charley's hand, and all his warm
+Southern blood flamed in his face.  Then, not to be outdone in
+generosity, he insisted on paying his fine and lawyer's fee
+himself, and flew half-way into a passion because Charley refused
+to let him.
+</para>
+
+<para>
+More than anything else we ever did, I think, this action of
+Charley's impressed upon the fishermen the deeper significance of
+the law.  Also Charley was raised high in their esteem, while I
+came in for a little share of praise as a boy who knew how to sail
+a boat.  Demetrios Contos not only never broke the law again, but
+he became a very good friend of ours, and on more than one occasion
+he ran up to Benicia to have a gossip with us.
+</para>
+
+
+</chapter>
+
+<chapter>
+<title>YELLOW HANDKERCHIEF</title>
+
+
+<para>
+"I'm not wanting to dictate to you, lad," Charley said; "but I'm
+very much against your making a last raid.  You've gone safely
+through rough times with rough men, and it would be a shame to have
+something happen to you at the very end."
+</para>
+
+<para>
+"But how can I get out of making a last raid?" I demanded, with the
+cocksureness of youth.  "There always has to be a last, you know,
+to anything."
+</para>
+
+<para>
+Charley crossed his legs, leaned back, and considered the problem.
+"Very true.  But why not call the capture of Demetrios Contos the
+last?  You're back from it safe and sound and hearty, for all your
+good wetting, and - and - "  His voice broke and he could not speak
+for a moment.  "And I could never forgive myself if anything
+happened to you now."
+</para>
+
+<para>
+I laughed at Charley's fears while I gave in to the claims of his
+affection, and agreed to consider the last raid already performed.
+We had been together for two years, and now I was leaving the fish
+patrol in order to go back and finish my education.  I had earned
+and saved money to put me through three years at the high school,
+and though the beginning of the term was several months away, I
+intended doing a lot of studying for the entrance examinations.
+</para>
+
+<para>
+My belongings were packed snugly in a sea-chest, and I was all
+ready to buy my ticket and ride down on the train to Oakland, when
+Neil Partington arrived in Benicia.  The Reindeer was needed
+immediately for work far down on the Lower Bay, and Neil said he
+intended to run straight for Oakland.  As that was his home and as
+I was to live with his family while going to school, he saw no
+reason, he said, why I should not put my chest aboard and come
+along.
+</para>
+
+<para>
+So the chest went aboard, and in the middle of the afternoon we
+hoisted the Reindeer's big mainsail and cast off.  It was
+tantalizing fall weather.  The sea-breeze, which had blown steadily
+all summer, was gone, and in its place were capricious winds and
+murky skies which made the time of arriving anywhere extremely
+problematical.  We started on the first of the ebb, and as we
+slipped down the Carquinez Straits, I looked my last for some time
+upon Benicia and the bight at Turner's Shipyard, where we had
+besieged the Lancashire Queen, and had captured Big Alec, the King
+of the Greeks.  And at the mouth of the Straits I looked with not a
+little interest upon the spot where a few days before I should have
+drowned but for the good that was in the nature of Demetrios
+Contos.
+</para>
+
+<para>
+A great wall of fog advanced across San Pablo Bay to meet us, and
+in a few minutes the Reindeer was running blindly through the damp
+obscurity.  Charley, who was steering, seemed to have an instinct
+for that kind of work.  How he did it, he himself confessed that he
+did not know; but he had a way of calculating winds, currents,
+distance, time, drift, and sailing speed that was truly marvellous.
+</para>
+
+<para>
+"It looks as though it were lifting," Neil Partington said, a
+couple of hours after we had entered the fog.  "Where do you say we
+are, Charley?"
+</para>
+
+<para>
+Charley looked at his watch, "Six o'clock, and three hours more of
+ebb," he remarked casually.
+</para>
+
+<para>
+"But where do you say we are?" Neil insisted.
+</para>
+
+<para>
+Charley pondered a moment, and then answered, "The tide has edged
+us over a bit out of our course, but if the fog lifts right now, as
+it is going to lift, you'll find we're not more than a thousand
+miles off McNear's Landing."
+</para>
+
+<para>
+"You might be a little more definite by a few miles, anyway," Neil
+grumbled, showing by his tone that he disagreed.
+</para>
+
+<para>
+"All right, then," Charley said, conclusively, "not less than a
+quarter of a mile, not more than a half."
+</para>
+
+<para>
+The wind freshened with a couple of little puffs, and the fog
+thinned perceptibly.
+</para>
+
+<para>
+"McNear's is right off there," Charley said, pointing directly into
+the fog on our weather beam.
+</para>
+
+<para>
+The three of us were peering intently in that direction, when the
+Reindeer struck with a dull crash and came to a standstill.  We ran
+forward, and found her bowsprit entangled in the tanned rigging of
+a short, chunky mast.  She had collided, head on, with a Chinese
+junk lying at anchor.
+</para>
+
+<para>
+At the moment we arrived forward, five Chinese, like so many bees,
+came swarming out of the little 'tween-decks cabin, the sleep still
+in their eyes.
+</para>
+
+<para>
+Leading them came a big, muscular man, conspicuous for his pock-
+marked face and the yellow silk handkerchief swathed about his
+head.  It was Yellow Handkerchief, the Chinaman whom we had
+arrested for illegal shrimp-fishing the year before, and who, at
+that time, had nearly sunk the Reindeer, as he had nearly sunk it
+now by violating the rules of navigation.
+</para>
+
+<para>
+"What d'ye mean, you yellow-faced heathen, lying here in a fairway
+without a horn a-going?" Charley cried hotly.
+</para>
+
+<para>
+"Mean?" Neil calmly answered.  "Just take a look - that's what he
+means."
+</para>
+
+<para>
+Our eyes followed the direction indicated by Neil's finger, and we
+saw the open amidships of the junk, half filled, as we found on
+closer examination, with fresh-caught shrimps.  Mingled with the
+shrimps were myriads of small fish, from a quarter of an inch
+upward in size.
+</para>
+
+<para>
+Yellow Handkerchief had lifted the trap-net at high-water slack,
+and, taking advantage of the concealment offered by the fog, had
+boldly been lying by, waiting to lift the net again at low-water
+slack.
+</para>
+
+<para>
+"Well," Neil hummed and hawed, "in all my varied and extensive
+experience as a fish patrolman, I must say this is the easiest
+capture I ever made.  What'll we do with them, Charley?"
+</para>
+
+<para>
+"Tow the junk into San Rafael, of course," came the answer.
+Charley turned to me.  "You stand by the junk, lad, and I'll pass
+you a towing line.  If the wind doesn't fail us, we'll make the
+creek before the tide gets too low, sleep at San Rafael, and arrive
+in Oakland to-morrow by midday."
+</para>
+
+<para>
+So saying, Charley and Neil returned to the Reindeer and got under
+way, the junk towing astern.  I went aft and took charge of the
+prize, steering by means of an antiquated tiller and a rudder with
+large, diamond-shaped holes, through which the water rushed back
+and forth.
+</para>
+
+<para>
+By now the last of the fog had vanished, and Charley's estimate of
+our position was confirmed by the sight of McNear's Landing a short
+half-mile away.  Following along the west shore, we rounded Point
+Pedro in plain view of the Chinese shrimp villages, and a great to-
+do was raised when they saw one of their junks towing behind the
+familiar fish patrol sloop.
+</para>
+
+<para>
+The wind, coming off the land, was rather puffy and uncertain, and
+it would have been more to our advantage had it been stronger.  San
+Rafael Creek, up which we had to go to reach the town and turn over
+our prisoners to the authorities, ran through wide-stretching
+marshes, and was difficult to navigate on a falling tide, while at
+low tide it was impossible to navigate at all.  So, with the tide
+already half-ebbed, it was necessary for us to make time.  This the
+heavy junk prevented, lumbering along behind and holding the
+Reindeer back by just so much dead weight.
+</para>
+
+<para>
+"Tell those coolies to get up that sail," Charley finally called to
+me.  "We don't want to hang up on the mud flats for the rest of the
+night."
+</para>
+
+<para>
+I repeated the order to Yellow Handkerchief, who mumbled it huskily
+to his men.  He was suffering from a bad cold, which doubled him up
+in convulsive coughing spells and made his eyes heavy and
+bloodshot.  This made him more evil-looking than ever, and when he
+glared viciously at me I remembered with a shiver the close shave I
+had had with him at the time of his previous arrest.
+</para>
+
+<para>
+His crew sullenly tailed on to the halyards, and the strange,
+outlandish sail, lateen in rig and dyed a warm brown, rose in the
+air.  We were sailing on the wind, and when Yellow Handkerchief
+flattened down the sheet the junk forged ahead and the tow-line
+went slack.  Fast as the Reindeer could sail, the junk outsailed
+her; and to avoid running her down I hauled a little closer on the
+wind.  But the junk likewise outpointed, and in a couple of minutes
+I was abreast of the Reindeer and to windward.  The tow-line had
+now tautened, at right angles to the two boats, and the predicament
+was laughable.
+</para>
+
+<para>
+"Cast off!" I shouted.
+</para>
+
+<para>
+Charley hesitated.
+</para>
+
+<para>
+"It's all right," I added.  "Nothing can happen.  We'll make the
+creek on this tack, and you'll be right behind me all the way up to
+San Rafael."
+</para>
+
+<para>
+At this Charley cast off, and Yellow Handkerchief sent one of his
+men forward to haul in the line.  In the gathering darkness I could
+just make out the mouth of San Rafael Creek, and by the time we
+entered it I could barely see its banks.  The Reindeer was fully
+five minutes astern, and we continued to leave her astern as we
+beat up the narrow, winding channel.  With Charley behind us, it
+seemed I had little to fear from my five prisoners; but the
+darkness prevented my keeping a sharp eye on them, so I transferred
+my revolver from my trousers pocket to the side pocket of my coat,
+where I could more quickly put my hand on it.
+</para>
+
+<para>
+Yellow Handkerchief was the one I feared, and that he knew it and
+made use of it, subsequent events will show.  He was sitting a few
+feet away from me, on what then happened to be the weather side of
+the junk.  I could scarcely see the outlines of his form, but I
+soon became convinced that he was slowly, very slowly, edging
+closer to me.  I watched him carefully.  Steering with my left
+hand, I slipped my right into my pocket and got hold of the
+revolver.
+</para>
+
+<para>
+I saw him shift along for a couple of inches, and I was just about
+to order him back - the words were trembling on the tip of my
+tongue - when I was struck with great force by a heavy figure that
+had leaped through the air upon me from the lee side.  It was one
+of the crew.  He pinioned my right arm so that I could not withdraw
+my hand from my pocket, and at the same time clapped his other hand
+over my mouth.  Of course, I could have struggled away from him and
+freed my hand or gotten my mouth clear so that I might cry an
+alarm, but in a trice Yellow Handkerchief was on top of me.
+</para>
+
+<para>
+I struggled around to no purpose in the bottom of the junk, while
+my legs and arms were tied and my mouth securely bound in what I
+afterward found to be a cotton shirt.  Then I was left lying in the
+bottom.  Yellow Handkerchief took the tiller, issuing his orders in
+whispers; and from our position at the time, and from the
+alteration of the sail, which I could dimly make out above me as a
+blot against the stars, I knew the junk was being headed into the
+mouth of a small slough which emptied at that point into San Rafael
+Creek.
+</para>
+
+<para>
+In a couple of minutes we ran softly alongside the bank, and the
+sail was silently lowered.  The Chinese kept very quiet.  Yellow
+Handkerchief sat down in the bottom alongside of me, and I could
+feel him straining to repress his raspy, hacking cough.  Possibly
+seven or eight minutes later I heard Charley's voice as the
+Reindeer went past the mouth of the slough.
+</para>
+
+<para>
+"I can't tell you how relieved I am," I could plainly hear him
+saying to Neil, "that the lad has finished with the fish patrol
+without accident."
+</para>
+
+<para>
+Here Neil said something which I could not catch, and then
+Charley's voice went on:
+</para>
+
+<para>
+"The youngster takes naturally to the water, and if, when he
+finishes high school, he takes a course in navigation and goes deep
+sea, I see no reason why he shouldn't rise to be master of the
+finest and biggest ship afloat."
+</para>
+
+<para>
+It was all very flattering to me, but lying there, bound and gagged
+by my own prisoners, with the voices growing faint and fainter as
+the Reindeer slipped on through the darkness toward San Rafael, I
+must say I was not in quite the proper situation to enjoy my
+smiling future.  With the Reindeer went my last hope.  What was to
+happen next I could not imagine, for the Chinese were a different
+race from mine, and from what I knew I was confident that fair play
+was no part of their make-up.
+</para>
+
+<para>
+After waiting a few minutes longer, the crew hoisted the lateen
+sail, and Yellow Handkerchief steered down toward the mouth of San
+Rafael Creek.  The tide was getting lower, and he had difficulty in
+escaping the mud-banks.  I was hoping he would run aground, but he
+succeeded in making the Bay without accident.
+</para>
+
+<para>
+As we passed out of the creek a noisy discussion arose, which I
+knew related to me.  Yellow Handkerchief was vehement, but the
+other four as vehemently opposed him.  It was very evident that he
+advocated doing away with me and that they were afraid of the
+consequences.  I was familiar enough with the Chinese character to
+know that fear alone restrained them.  But what plan they offered
+in place of Yellow Handkerchief's murderous one, I could not make
+out.
+</para>
+
+<para>
+My feelings, as my fate hung in the balance, may be guessed.  The
+discussion developed into a quarrel, in the midst of which Yellow
+Handkerchief unshipped the heavy tiller and sprang toward me.  But
+his four companions threw themselves between, and a clumsy struggle
+took place for possession of the tiller.  In the end Yellow
+Handkerchief was overcome, and sullenly returned to the steering,
+while they soundly berated him for his rashness.
+</para>
+
+<para>
+Not long after, the sail was run down and the junk slowly urged
+forward by means of the sweeps.  I felt it ground gently on the
+soft mud.  Three of the Chinese - they all wore long sea-boots -
+got over the side, and the other two passed me across the rail.
+With Yellow Handkerchief at my legs and his two companions at my
+shoulders, they began to flounder along through the mud.  After
+some time their feet struck firmer footing, and I knew they were
+carrying me up some beach.  The location of this beach was not
+doubtful in my mind.  It could be none other than one of the Marin
+Islands, a group of rocky islets which lay off the Marin County
+shore.
+</para>
+
+<para>
+When they reached the firm sand that marked high tide, I was
+dropped, and none too gently.  Yellow Handkerchief kicked me
+spitefully in the ribs, and then the trio floundered back through
+the mud to the junk.  A moment later I heard the sail go up and
+slat in the wind as they drew in the sheet.  Then silence fell, and
+I was left to my own devices for getting free.
+</para>
+
+<para>
+I remembered having seen tricksters writhe and squirm out of ropes
+with which they were bound, but though I writhed and squirmed like
+a good fellow, the knots remained as hard as ever, and there was no
+appreciable slack.  In the course of my squirming, however, I
+rolled over upon a heap of clam-shells - the remains, evidently, of
+some yachting party's clam-bake.  This gave me an idea.  My hands
+were tied behind my back; and, clutching a shell in them, I rolled
+over and over, up the beach, till I came to the rocks I knew to be
+there.
+</para>
+
+<para>
+Rolling around and searching, I finally discovered a narrow
+crevice, into which I shoved the shell.  The edge of it was sharp,
+and across the sharp edge I proceeded to saw the rope that bound my
+wrists.  The edge of the shell was also brittle, and I broke it by
+bearing too heavily upon it.  Then I rolled back to the heap and
+returned with as many shells as I could carry in both hands.  I
+broke many shells, cut my hands a number of times, and got cramps
+in my legs from my strained position and my exertions.
+</para>
+
+<para>
+While I was suffering from the cramps, and resting, I heard a
+familiar halloo drift across the water.  It was Charley, searching
+for me.  The gag in my mouth prevented me from replying, and I
+could only lie there, helplessly fuming, while he rowed past the
+island and his voice slowly lost itself in the distance.
+</para>
+
+<para>
+I returned to the sawing process, and at the end of half an hour
+succeeded in severing the rope.  The rest was easy.  My hands once
+free, it was a matter of minutes to loosen my legs and to take the
+gag out of my mouth.  I ran around the island to make sure it was
+an island and not by any chance a portion of the mainland.  An
+island it certainly was, one of the Marin group, fringed with a
+sandy beach and surrounded by a sea of mud.  Nothing remained but
+to wait till daylight and to keep warm; for it was a cold, raw
+night for California, with just enough wind to pierce the skin and
+cause one to shiver.
+</para>
+
+<para>
+To keep up the circulation, I ran around the island a dozen times
+or so, and clambered across its rocky backbone as many times more -
+all of which was of greater service to me, as I afterward
+discovered, than merely to warm me up.  In the midst of this
+exercise I wondered if I had lost anything out of my pockets while
+rolling over and over in the sand.  A search showed the absence of
+my revolver and pocket-knife.  The first Yellow Handkerchief had
+taken; but the knife had been lost in the sand.
+</para>
+
+<para>
+I was hunting for it when the sound of rowlocks came to my ears.
+At first, of course, I thought of Charley; but on second thought I
+knew Charley would be calling out as he rowed along.  A sudden
+premonition of danger seized me.  The Marin Islands are lonely
+places; chance visitors in the dead of night are hardly to be
+expected.  What if it were Yellow Handkerchief?  The sound made by
+the rowlocks grew more distinct.  I crouched in the sand and
+listened intently.  The boat, which I judged a small skiff from the
+quick stroke of the oars, was landing in the mud about fifty yards
+up the beach.  I heard a raspy, hacking cough, and my heart stood
+still.  It was Yellow Handkerchief.  Not to be robbed of his
+revenge by his more cautious companions, he had stolen away from
+the village and come back alone.
+</para>
+
+<para>
+I did some swift thinking.  I was unarmed and helpless on a tiny
+islet, and a yellow barbarian, whom I had reason to fear, was
+coming after me.  Any place was safer than the island, and I turned
+instinctively to the water, or rather to the mud.  As he began to
+flounder ashore through the mud, I started to flounder out into it,
+going over the same course which the Chinese had taken in landing
+me and in returning to the junk.
+</para>
+
+<para>
+Yellow Handkerchief, believing me to be lying tightly bound,
+exercised no care, but came ashore noisily.  This helped me, for,
+under the shield of his noise and making no more myself than
+necessary, I managed to cover fifty feet by the time he had made
+the beach.  Here I lay down in the mud.  It was cold and clammy,
+and made me shiver, but I did not care to stand up and run the risk
+of being discovered by his sharp eyes.
+</para>
+
+<para>
+He walked down the beach straight to where he had left me lying,
+and I had a fleeting feeling of regret at not being able to see his
+surprise when he did not find me.  But it was a very fleeting
+regret, for my teeth were chattering with the cold.
+</para>
+
+<para>
+What his movements were after that I had largely to deduce from the
+facts of the situation, for I could scarcely see him in the dim
+starlight.  But I was sure that the first thing he did was to make
+the circuit of the beach to learn if landings had been made by
+other boats.  This he would have known at once by the tracks
+through the mud.
+</para>
+
+<para>
+Convinced that no boat had removed me from the island, he next
+started to find out what had become of me.  Beginning at the pile
+of clamshells, he lighted matches to trace my tracks in the sand.
+At such times I could see his villanous face plainly, and, when the
+sulphur from the matches irritated his lungs, between the raspy
+cough that followed and the clammy mud in which I was lying, I
+confess I shivered harder than ever.
+</para>
+
+<para>
+The multiplicity of my footprints puzzled him.  Then the idea that
+I might be out in the mud must have struck him, for he waded out a
+few yards in my direction, and, stooping, with his eyes searched
+the dim surface long and carefully.  He could not have been more
+than fifteen feet from me, and had he lighted a match he would
+surely have discovered me.
+</para>
+
+<para>
+He returned to the beach and clambered about, over the rocky
+backbone, again hunting for me with lighted matches, The closeness
+of the shave impelled me to further flight.  Not daring to wade
+upright, on account of the noise made by floundering and by the
+suck of the mud, I remained lying down in the mud and propelled
+myself over its surface by means of my hands.  Still keeping the
+trail made by the Chinese in going from and to the junk, I held on
+until I reached the water.  Into this I waded to a depth of three
+feet, and then I turned off to the side on a line parallel with the
+beach.
+</para>
+
+<para>
+The thought came to me of going toward Yellow Handkerchief's skiff
+and escaping in it, but at that very moment he returned to the
+beach, and, as though fearing the very thing I had in mind, he
+slushed out through the mud to assure himself that the skiff was
+safe.  This turned me in the opposite direction.  Half swimming,
+half wading, with my head just out of water and avoiding splashing,
+I succeeded in putting about a hundred feet between myself and the
+spot where the Chinese had begun to wade ashore from the junk.  I
+drew myself out on the mud and remained lying flat.
+</para>
+
+<para>
+Again Yellow Handkerchief returned to the beach and made a search
+of the island, and again he returned to the heap of clam-shells.  I
+knew what was running in his mind as well as he did himself.  No
+one could leave or land without making tracks in the mud.  The only
+tracks to be seen were those leading from his skiff and from where
+the junk had been.  I was not on the island.  I must have left it
+by one or the other of those two tracks.  He had just been over the
+one to his skiff, and was certain I had not left that way.
+Therefore I could have left the island only by going over the
+tracks of the junk landing.  This he proceeded to verify by wading
+out over them himself, lighting matches as he came along.
+</para>
+
+<para>
+When he arrived at the point where I had first lain, I knew, by the
+matches he burned and the time he took, that he had discovered the
+marks left by my body.  These he followed straight to the water and
+into it, but in three feet of water he could no longer see them.
+On the other hand, as the tide was still falling, he could easily
+make out the impression made by the junk's bow, and could have
+likewise made out the impression of any other boat if it had landed
+at that particular spot.  But there was no such mark; and I knew
+that he was absolutely convinced that I was hiding somewhere in the
+mud.
+</para>
+
+<para>
+But to hunt on a dark night for a boy in a sea of mud would be like
+hunting for a needle in a haystack, and he did not attempt it.
+Instead he went back to the beach and prowled around for some time.
+I was hoping he would give me up and go, for by this time I was
+suffering severely from the cold.  At last he waded out to his
+skiff and rowed away.  What if this departure of Yellow
+Handkerchief's were a sham?  What if he had done it merely to
+entice me ashore?
+</para>
+
+<para>
+The more I thought of it the more certain I became that he had made
+a little too much noise with his oars as he rowed away.  So I
+remained, lying in the mud and shivering.  I shivered till the
+muscles of the small of my back ached and pained me as badly as the
+cold, and I had need of all my self-control to force myself to
+remain in my miserable situation.
+</para>
+
+<para>
+It was well that I did, however, for, possibly an hour later, I
+thought I could make out something moving on the beach.  I watched
+intently, but my ears were rewarded first, by a raspy cough I knew
+only too well.  Yellow Handkerchief had sneaked back, landed on the
+other side of the island, and crept around to surprise me if I had
+returned.
+</para>
+
+<para>
+After that, though hours passed without sign of him, I was afraid
+to return to the island at all.  On the other hand, I was almost
+equally afraid that I should die of the exposure I was undergoing.
+I had never dreamed one could suffer so.  I grew so cold and numb,
+finally, that I ceased to shiver.  But my muscles and bones began
+to ache in a way that was agony.  The tide had long since begun to
+rise, and, foot by foot, it drove me in toward the beach.  High
+water came at three o'clock, and at three o'clock I drew myself up
+on the beach, more dead than alive, and too helpless to have
+offered any resistance had Yellow Handkerchief swooped down upon
+me.
+</para>
+
+<para>
+But no Yellow Handkerchief appeared.  He had given me up and gone
+back to Point Pedro.  Nevertheless, I was in a deplorable, not to
+say dangerous, condition.  I could not stand upon my feet, much
+less walk.  My clammy, muddy garments clung to me like sheets of
+ice.  I thought I should never get them off.  So numb and lifeless
+were my fingers, and so weak was I, that it seemed to take an hour
+to get off my shoes.  I had not the strength to break the porpoise-
+hide laces, and the knots defied me.  I repeatedly beat my hands
+upon the rocks to get some sort of life into them.  Sometimes I
+felt sure I was going to die.
+</para>
+
+<para>
+But in the end, - after several centuries, it seemed to me, - I got
+off the last of my clothes.  The water was now close at hand, and I
+crawled painfully into it and washed the mud from my naked body.
+Still, I could not get on my feet and walk and I was afraid to lie
+still.  Nothing remained but to crawl weakly, like a snail, and at
+the cost of constant pain, up and down the sand.  I kept this up as
+long as possible, but as the east paled with the coming of dawn I
+began to succumb.  The sky grew rosy-red, and the golden rim of the
+sun, showing above the horizon, found me lying helpless and
+motionless among the clam-shells.
+</para>
+
+<para>
+As in a dream, I saw the familiar mainsail of the Reindeer as she
+slipped out of San Rafael Creek on a light puff of morning air.
+This dream was very much broken.  There are intervals I can never
+recollect on looking back over it.  Three things, however, I
+distinctly remember:  the first sight of the Reindeer's mainsail;
+her lying at anchor a few hundred feet away and a small boat
+leaving her side; and the cabin stove roaring red-hot, myself
+swathed all over with blankets, except on the chest and shoulders,
+which Charley was pounding and mauling unmercifully, and my mouth
+and throat burning with the coffee which Neil Partington was
+pouring down a trifle too hot.
+</para>
+
+<para>
+But burn or no burn, I tell you it felt good.  By the time we
+arrived in Oakland I was as limber and strong as ever, - though
+Charlie and Neil Partington were afraid I was going to have
+pneumonia, and Mrs. Partington, for my first six months of school,
+kept an anxious eye upon me to discover the first symptoms of
+consumption.
+</para>
+
+<para>
+Time flies.  It seems but yesterday that I was a lad of sixteen on
+the fish patrol.  Yet I know that I arrived this very morning from
+China, with a quick passage to my credit, and master of the
+barkentine Harvester.  And I know that to-morrow morning I shall
+run over to Oakland to see Neil Partington and his wife and family,
+and later on up to Benicia to see Charley Le Grant and talk over
+old times.  No; I shall not go to Benicia, now that I think about
+it.  I expect to be a highly interested party to a wedding, shortly
+to take place.  Her name is Alice Partington, and, since Charley
+has promised to be best man, he will have to come down to Oakland
+instead.
+</para>
+</chapter>
+
+</bookbody>
+</book>
+<endgutblurb>
+End of Project Gutenberg's Etext of Tales of the Fish Patrol, by London
+</endgutblurb>
+
+</gutbook>
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/import/gutbook1.dtd
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/import/gutbook1.dtd	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/import/gutbook1.dtd	(revision 14125)
@@ -0,0 +1,40 @@
+<!--
+GUTBOOK DTD V 1.0
+==================
+
+GENERAL NOTES
++++++++++++++
+This is gutbook dtd version 1.0
+file name is gutpoems1.dtd
+This dtd is a first pass at a dtd for marking up 
+books for project gutenberg.
+It was originally developed for marking up the Darwins books.
+
+REVISION HISTORY
+++++++++++++++++
+Original Author
+Frank Boumphrey  1/19/2000
+
+COPYRIGHT NOTICE
+++++++++++++++++
+This DTD is the copyright of the HTML writers guild.
+Permission is given in perpetuity for any one to use 
+this DTD provided that these notes and this  copyright 
+notice is included.
+
+
+-->
+
+<!--Begin gutbook DTD-->
+<!ELEMENT gutbook (gutblurb,markupblurb,book*,endmarkupblurb?,endgutblurb?)>
+
+<!ELEMENT gutblurb (#PCDATA|para|simplesect|title)*>
+<!ELEMENT markupblurb (#PCDATA|para|simplesect|title)*>
+<!ELEMENT endmarkupblurb (#PCDATA|para|simplesect|title)*>
+<!ELEMENT endgutblurb (#PCDATA|para|simplesect|title)*>
+
+<!--Include bookfrag.dtd-->
+
+<!ENTITY % bookfrag SYSTEM "bookfrag.dtd">
+%bookfrag;
+<!--end of file-->
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/import/iliad.xml
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/import/iliad.xml	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/import/iliad.xml	(revision 14125)
@@ -0,0 +1,16976 @@
+<?xml version="1.0"?>
+<!DOCTYPE gutbook SYSTEM "gutbook1.dtd">
+
+<?xml-stylesheet type="text/css" href="darwin.css"?>
+
+<gutbook>
+<gutblurb>
+<para>
+*******The Project Gutenberg Etext of The Iliad, by Homer*****
+translated by Samuel Butler
+#3 in our series by Homer
+</para>
+
+<para>
+Copyright laws are changing all over the world, be sure to check
+the copyright laws for your country before posting these files!!
+</para>
+
+<para>
+Please take a look at the important information in this header.
+We encourage you to keep this file on your own disk, keeping an
+electronic path open for the next readers.  Do not remove this.
+</para>
+
+<para>
+**Welcome To The World of Free Plain Vanilla Electronic Texts**
+</para>
+
+<para>
+**Etexts Readable By Both Humans and By Computers, Since 1971**
+</para>
+
+<para>
+*These Etexts Prepared By Hundreds of Volunteers and Donations*
+</para>
+
+<para>
+Information on contacting Project Gutenberg to get Etexts, and
+further information is included below.  We need your donations.
+</para>
+
+<para>
+The Iliad of Homer
+</para>
+
+<para>
+translated by Samuel Butler
+</para>
+
+<para>
+June, 2000  [Etext #2199]
+</para>
+
+<para>
+********The Project Gutenberg Etext of The Iliad, by Homer******
+******This file should be named iliad10.txt or iliad10.zip******
+</para>
+
+<para>
+Corrected EDITIONS of our etexts get a new NUMBER, iliad11.txt
+VERSIONS based on separate sources get new LETTER, iliad10a.txt
+</para>
+
+<para>
+Project Gutenberg Etexts are usually created from multiple editions,
+all of which are in the Public Domain in the United States, unless a
+copyright notice is included.  Therefore, we do NOT keep these books
+in compliance with any particular paper edition, usually otherwise.
+</para>
+
+<para>
+We are now trying to release all our books one month in advance
+of the official release dates, for time for better editing.
+</para>
+
+<para>
+Please note:  neither this list nor its contents are final till
+midnight of the last day of the month of any such announcement.
+The official release date of all Project Gutenberg Etexts is at
+Midnight, Central Time, of the last day of the stated month.  A
+preliminary version may often be posted for suggestion, comment
+and editing by those who wish to do so.  To be sure you have an
+up to date first edition [xxxxx10x.xxx] please check file sizes
+in the first week of the next month.  Since our ftp program has
+a bug in it that scrambles the date [tried to fix and failed] a
+look at the file size will have to do, but we will try to see a
+new copy has at least one byte more or less.
+</para>
+
+<para>
+Information about Project Gutenberg (one page)
+</para>
+
+<para>
+We produce about two million dollars for each hour we work.  The
+fifty hours is one conservative estimate for how long it we take
+to get any etext selected, entered, proofread, edited, copyright
+searched and analyzed, the copyright letters written, etc.  This
+projected audience is one hundred million readers.  If our value
+per text is nominally estimated at one dollar then we produce $2
+million dollars per hour this year as we release thirty-two text
+files per month, or 384 more Etexts in 1998 for a total of 1500+
+If these reach just 10% of the computerized population, then the
+total should reach over 150 billion Etexts given away.
+</para>
+
+<para>
+The Goal of Project Gutenberg is to Give Away One Trillion Etext
+Files by the December 31, 2001.  [10,000 x 100,000,000=Trillion]
+This is ten thousand titles each to one hundred million readers,
+which is only 10% of the present number of computer users.  2001
+should have at least twice as many computer users as that, so it
+will require us reaching less than 5% of the users in 2001.
+</para>
+
+<para>
+We need your donations more than ever!
+</para>
+
+<para>
+All donations should be made to "Project Gutenberg/CMU": and are
+tax deductible to the extent allowable by law.  (CMU = Carnegie-
+Mellon University).
+</para>
+
+<para>
+For these and other matters, please mail to:
+</para>
+
+<para>
+Project Gutenberg
+P. O. Box  2782
+Champaign, IL 61825
+</para>
+
+<para>
+When all other email fails try our Executive Director:
+Michael S. Hart hart@pobox.com
+</para>
+
+<para>
+We would prefer to send you this information by email
+(Internet, Bitnet, Compuserve, ATTMAIL or MCImail).
+</para>
+
+<para>
+******
+If you have an FTP program (or emulator), please
+FTP directly to the Project Gutenberg archives:
+[Mac users, do NOT point and click. . .type]
+</para>
+
+<para>
+ftp uiarchive.cso.uiuc.edu
+login:  anonymous
+password:  your@login
+cd etext/etext90 through /etext96
+or cd etext/articles [get suggest gut for more information]
+dir [to see files]
+get or mget [to get files. . .set bin for zip files]
+GET INDEX?00.GUT
+for a list of books
+and
+GET NEW GUT for general information
+and
+MGET GUT* for newsletters.
+</para>
+
+<para>
+**Information prepared by the Project Gutenberg legal advisor**
+(Three Pages)
+</para>
+
+<para>
+***START**THE SMALL PRINT!**FOR PUBLIC DOMAIN ETEXTS**START***
+Why is this "Small Print!" statement here?  You know: lawyers.
+They tell us you might sue us if there is something wrong with
+your copy of this etext, even if you got it for free from
+someone other than us, and even if what's wrong is not our
+fault.  So, among other things, this "Small Print!" statement
+disclaims most of our liability to you.  It also tells you how
+you can distribute copies of this etext if you want to.
+</para>
+
+<para>
+*BEFORE!* YOU USE OR READ THIS ETEXT
+By using or reading any part of this PROJECT GUTENBERG-tm
+etext, you indicate that you understand, agree to and accept
+this "Small Print!" statement.  If you do not, you can receive
+a refund of the money (if any) you paid for this etext by
+sending a request within 30 days of receiving it to the person
+you got it from.  If you received this etext on a physical
+medium (such as a disk), you must return it with your request.
+</para>
+
+<para>
+ABOUT PROJECT GUTENBERG-TM ETEXTS
+This PROJECT GUTENBERG-tm etext, like most PROJECT GUTENBERG-
+tm etexts, is a "public domain" work distributed by Professor
+Michael S. Hart through the Project Gutenberg Association at
+Carnegie-Mellon University (the "Project").  Among other
+things, this means that no one owns a United States copyright
+on or for this work, so the Project (and you!) can copy and
+distribute it in the United States without permission and
+without paying copyright royalties.  Special rules, set forth
+below, apply if you wish to copy and distribute this etext
+under the Project's "PROJECT GUTENBERG" trademark.
+</para>
+
+<para>
+To create these etexts, the Project expends considerable
+efforts to identify, transcribe and proofread public domain
+works.  Despite these efforts, the Project's etexts and any
+medium they may be on may contain "Defects".  Among other
+things, Defects may take the form of incomplete, inaccurate or
+corrupt data, transcription errors, a copyright or other
+intellectual property infringement, a defective or damaged
+disk or other etext medium, a computer virus, or computer
+codes that damage or cannot be read by your equipment.
+</para>
+
+<para>
+LIMITED WARRANTY; DISCLAIMER OF DAMAGES
+But for the "Right of Replacement or Refund" described below,
+[1] the Project (and any other party you may receive this
+etext from as a PROJECT GUTENBERG-tm etext) disclaims all
+liability to you for damages, costs and expenses, including
+legal fees, and [2] YOU HAVE NO REMEDIES FOR NEGLIGENCE OR
+UNDER STRICT LIABILITY, OR FOR BREACH OF WARRANTY OR CONTRACT,
+INCLUDING BUT NOT LIMITED TO INDIRECT, CONSEQUENTIAL, PUNITIVE
+OR INCIDENTAL DAMAGES, EVEN IF YOU GIVE NOTICE OF THE
+POSSIBILITY OF SUCH DAMAGES.
+</para>
+
+<para>
+If you discover a Defect in this etext within 90 days of
+receiving it, you can receive a refund of the money (if any)
+you paid for it by sending an explanatory note within that
+time to the person you received it from.  If you received it
+on a physical medium, you must return it with your note, and
+such person may choose to alternatively give you a replacement
+copy.  If you received it electronically, such person may
+choose to alternatively give you a second opportunity to
+receive it electronically.
+</para>
+
+<para>
+THIS ETEXT IS OTHERWISE PROVIDED TO YOU "AS-IS".  NO OTHER
+WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, ARE MADE TO YOU AS
+TO THE ETEXT OR ANY MEDIUM IT MAY BE ON, INCLUDING BUT NOT
+LIMITED TO WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
+PARTICULAR PURPOSE.
+</para>
+
+<para>
+Some states do not allow disclaimers of implied warranties or
+the exclusion or limitation of consequential damages, so the
+above disclaimers and exclusions may not apply to you, and you
+may have other legal rights.
+</para>
+
+<para>
+INDEMNITY
+You will indemnify and hold the Project, its directors,
+officers, members and agents harmless from all liability, cost
+and expense, including legal fees, that arise directly or
+indirectly from any of the following that you do or cause:
+[1] distribution of this etext, [2] alteration, modification,
+or addition to the etext, or [3] any Defect.
+</para>
+
+<para>
+DISTRIBUTION UNDER "PROJECT GUTENBERG-tm"
+You may distribute copies of this etext electronically, or by
+disk, book or any other medium if you either delete this
+"Small Print!" and all other references to Project Gutenberg,
+or:
+</para>
+
+<para>
+[1]  Only give exact copies of it.  Among other things, this
+     requires that you do not remove, alter or modify the
+     etext or this "small print!" statement.  You may however,
+     if you wish, distribute this etext in machine readable
+     binary, compressed, mark-up, or proprietary form,
+     including any form resulting from conversion by word pro-
+     cessing or hypertext software, but only so long as
+     *EITHER*:
+</para>
+
+<para>
+     [*]  The etext, when displayed, is clearly readable, and
+          does *not* contain characters other than those
+          intended by the author of the work, although tilde
+          (~), asterisk (*) and underline (_) characters may
+          be used to convey punctuation intended by the
+          author, and additional characters may be used to
+          indicate hypertext links; OR
+</para>
+
+<para>
+     [*]  The etext may be readily converted by the reader at
+          no expense into plain ASCII, EBCDIC or equivalent
+          form by the program that displays the etext (as is
+          the case, for instance, with most word processors);
+          OR
+</para>
+
+<para>
+     [*]  You provide, or agree to also provide on request at
+          no additional cost, fee or expense, a copy of the
+          etext in its original plain ASCII form (or in EBCDIC
+          or other equivalent proprietary form).
+</para>
+
+<para>
+[2]  Honor the etext refund and replacement provisions of this
+     "Small Print!" statement.
+</para>
+
+<para>
+[3]  Pay a trademark license fee to the Project of 20% of the
+     net profits you derive calculated using the method you
+     already use to calculate your applicable taxes.  If you
+     don't derive profits, no royalty is due.  Royalties are
+     payable to "Project Gutenberg Association/Carnegie-Mellon
+     University" within the 60 days following each
+     date you prepare (or were legally required to prepare)
+     your annual (or equivalent periodic) tax return.
+</para>
+
+<para>
+WHAT IF YOU *WANT* TO SEND MONEY EVEN IF YOU DON'T HAVE TO?
+The Project gratefully accepts contributions in money, time,
+scanning machines, OCR software, public domain etexts, royalty
+free copyright licenses, and every other sort of contribution
+you can think of.  Money should be paid to "Project Gutenberg
+Association / Carnegie-Mellon University".
+</para>
+
+<para>
+*END*THE SMALL PRINT! FOR PUBLIC DOMAIN ETEXTS*Ver.04.29.93*END*
+</para>
+</gutblurb>
+
+<markupblurb>
+Marked up by Mark Stradling Feb 2000
+Validated against gutbook1.dtd using Mozilla M13 Feb 2000
+</markupblurb>
+
+<book>
+<acknowledge>
+A project of the HTML Writrs Guild and Project Gutenberg. Markup by Mark Stradling Feb 2000
+</acknowledge>
+<frontmatter>
+<titlepage>
+<title>THE ILIAD</title>
+<para> by</para>
+<author>HOMER</author>
+<para>
+Rendered into English Prose for
+the use of those who cannot
+read the original
+</para>
+
+<para>
+by Samuel Butler
+</para>
+</titlepage>
+</frontmatter>
+<bookbody>
+<chapter>
+<title>BOOK I</title>
+
+<para>
+Sing, O goddess, the anger of Achilles son of Peleus, that
+brought countless ills upon the Achaeans. Many a brave soul did
+it send hurrying down to Hades, and many a hero did it yield a
+prey to dogs and vultures, for so were the counsels of Jove
+fulfilled from the day on which the son of Atreus, king of men,
+and great Achilles, first fell out with one another.
+</para>
+
+<para>
+And which of the gods was it that set them on to quarrel? It was
+the son of Jove and Leto; for he was angry with the king and sent
+a pestilence upon the host to plague the people, because the son
+of Atreus had dishonoured Chryses his priest. Now Chryses had
+come to the ships of the Achaeans to free his daughter, and had
+brought with him a great ransom: moreover he bore in his hand the
+sceptre of Apollo wreathed with a suppliant's wreath, and he
+besought the Achaeans, but most of all the two sons of Atreus,
+who were their chiefs.
+</para>
+
+<para>
+"Sons of Atreus," he cried, "and all other Achaeans, may the gods
+who dwell in Olympus grant you to sack the city of Priam, and to
+reach your homes in safety; but free my daughter, and accept a
+ransom for her, in reverence to Apollo, son of Jove."
+</para>
+
+<para>
+On this the rest of the Achaeans with one voice were for
+respecting the priest and taking the ransom that he offered; but
+not so Agamemnon, who spoke fiercely to him and sent him roughly
+away. "Old man," said he, "let me not find you tarrying about our
+ships, nor yet coming hereafter. Your sceptre of the god and your
+wreath shall profit you nothing. I will not free her. She shall
+grow old in my house at Argos far from her own home, busying
+herself with her loom and visiting my couch; so go, and do not
+provoke me or it shall be the worse for you."
+</para>
+
+<para>
+The old man feared him and obeyed. Not a word he spoke, but went
+by the shore of the sounding sea and prayed apart to King Apollo
+whom lovely Leto had borne. "Hear me," he cried, "O god of the
+silver bow, that protectest Chryse and holy Cilla and rulest
+Tenedos with thy might, hear me oh thou of Sminthe. If I have
+ever decked your temple with garlands, or burned your thigh-bones
+in fat of bulls or goats, grant my prayer, and let your arrows
+avenge these my tears upon the Danaans."
+</para>
+
+<para>
+Thus did he pray, and Apollo heard his prayer. He came down
+furious from the summits of Olympus, with his bow and his quiver
+upon his shoulder, and the arrows rattled on his back with the
+rage that trembled within him. He sat himself down away from the
+ships with a face as dark as night, and his silver bow rang death
+as he shot his arrow in the midst of them. First he smote their
+mules and their hounds, but presently he aimed his shafts at the
+people themselves, and all day long the pyres of the dead were
+burning.
+</para>
+
+<para>
+For nine whole days he shot his arrows among the people, but upon
+the tenth day Achilles called them in assembly--moved thereto by
+Juno, who saw the Achaeans in their death-throes and had
+compassion upon them. Then, when they were got together, he rose
+and spoke among them.
+</para>
+
+<para>
+"Son of Atreus," said he, "I deem that we should now turn roving
+home if we would escape destruction, for we are being cut down by
+war and pestilence at once. Let us ask some priest or prophet, or
+some reader of dreams (for dreams, too, are of Jove) who can tell
+us why Phoebus Apollo is so angry, and say whether it is for some
+vow that we have broken, or hecatomb that we have not offered,
+and whether he will accept the savour of lambs and goats without
+blemish, so as to take away the plague from us."
+</para>
+
+<para>
+With these words he sat down, and Calchas son of Thestor, wisest
+of augurs, who knew things past present and to come, rose to
+speak. He it was who had guided the Achaeans with their fleet to
+Ilius, through the prophesyings with which Phoebus Apollo had
+inspired him. With all sincerity and goodwill he addressed them
+thus:--
+</para>
+
+<para>
+"Achilles, loved of heaven, you bid me tell you about the anger
+of King Apollo, I will therefore do so; but consider first and
+swear that you will stand by me heartily in word and deed, for I
+know that I shall offend one who rules the Argives with might, to
+whom all the Achaeans are in subjection. A plain man cannot stand
+against the anger of a king, who if he swallow his displeasure
+now, will yet nurse revenge till he has wreaked it. Consider,
+therefore, whether or no you will protect me."
+</para>
+
+<para>
+And Achilles answered, "Fear not, but speak as it is borne in
+upon you from heaven, for by Apollo, Calchas, to whom you pray,
+and whose oracles you reveal to us, not a Danaan at our ships
+shall lay his hand upon you, while I yet live to look upon the
+face of the earth--no, not though you name Agamemnon himself, who
+is by far the foremost of the Achaeans."
+</para>
+
+<para>
+Thereon the seer spoke boldly. "The god," he said, "is angry
+neither about vow nor hecatomb, but for his priest's sake, whom
+Agamemnon has dishonoured, in that he would not free his daughter
+nor take a ransom for her; therefore has he sent these evils upon
+us, and will yet send others. He will not deliver the Danaans
+from this pestilence till Agamemnon has restored the girl without
+fee or ransom to her father, and has sent a holy hecatomb to
+Chryse. Thus we may perhaps appease him."
+</para>
+
+<para>
+With these words he sat down, and Agamemnon rose in anger. His
+heart was black with rage, and his eyes flashed fire as he
+scowled on Calchas and said, "Seer of evil, you never yet
+prophesied smooth things concerning me, but have ever loved to
+foretell that which was evil. You have brought me neither comfort
+nor performance; and now you come seeing among Danaans, and
+saying that Apollo has plagued us because I would not take a
+ransom for this girl, the daughter of Chryses. I have set my
+heart on keeping her in my own house, for I love her better even
+than my own wife Clytemnestra, whose peer she is alike in form
+and feature, in understanding and accomplishments. Still I will
+give her up if I must, for I would have the people live, not die;
+but you must find me a prize instead, or I alone among the
+Argives shall be without one. This is not well; for you behold,
+all of you, that my prize is to go elsewhither."
+</para>
+
+<para>
+And Achilles answered, "Most noble son of Atreus, covetous beyond
+all mankind, how shall the Achaeans find you another prize? We
+have no common store from which to take one. Those we took from
+the cities have been awarded; we cannot disallow the awards that
+have been made already. Give this girl, therefore, to the god,
+and if ever Jove grants us to sack the city of Troy we will
+requite you three and fourfold."
+</para>
+
+<para>
+Then Agamemnon said, "Achilles, valiant though you be, you shall
+not thus outwit me. You shall not overreach and you shall not
+persuade me. Are you to keep your own prize, while I sit tamely
+under my loss and give up the girl at your bidding? Let the
+Achaeans find me a prize in fair exchange to my liking, or I will
+come and take your own, or that of Ajax or of Ulysses; and he to
+whomsoever I may come shall rue my coming. But of this we will
+take thought hereafter; for the present, let us draw a ship into
+the sea, and find a crew for her expressly; let us put a hecatomb
+on board, and let us send Chryseis also; further, let some chief
+man among us be in command, either Ajax, or Idomeneus, or
+yourself, son of Peleus, mighty warrior that you are, that we may
+offer sacrifice and appease the the anger of the god."
+</para>
+
+<para>
+Achilles scowled at him and answered, "You are steeped in
+insolence and lust of gain. With what heart can any of the
+Achaeans do your bidding, either on foray or in open fighting? I
+came not warring here for any ill the Trojans had done me. I have
+no quarrel with them. They have not raided my cattle nor my
+horses, nor cut down my harvests on the rich plains of Phthia;
+for between me and them there is a great space, both mountain and
+sounding sea. We have followed you, Sir Insolence! for your
+pleasure, not ours--to gain satisfaction from the Trojans for
+your shameless self and for Menelaus. You forget this, and
+threaten to rob me of the prize for which I have toiled, and
+which the sons of the Achaeans have given me. Never when the
+Achaeans sack any rich city of the Trojans do I receive so good a
+prize as you do, though it is my hands that do the better part of
+the fighting. When the sharing comes, your share is far the
+largest, and I, forsooth, must go back to my ships, take what I
+can get and be thankful, when my labour of fighting is done. Now,
+therefore, I shall go back to Phthia; it will be much better for
+me to return home with my ships, for I will not stay here
+dishonoured to gather gold and substance for you."
+</para>
+
+<para>
+And Agamemnon answered, "Fly if you will, I shall make you no
+prayers to stay you. I have others here who will do me honour,
+and above all Jove, the lord of counsel. There is no king here so
+hateful to me as you are, for you are ever quarrelsome and ill-
+affected. What though you be brave? Was it not heaven that made
+you so? Go home, then, with your ships and comrades to lord it
+over the Myrmidons. I care neither for you nor for your anger;
+and thus will I do: since Phoebus Apollo is taking Chryseis from
+me, I shall send her with my ship and my followers, but I shall
+come to your tent and take your own prize Briseis, that you may
+learn how much stronger I am than you are, and that another may
+fear to set himself up as equal or comparable with me."
+</para>
+
+<para>
+The son of Peleus was furious, and his heart within his shaggy
+breast was divided whether to draw his sword, push the others
+aside, and kill the son of Atreus, or to restrain himself and
+check his anger. While he was thus in two minds, and was drawing
+his mighty sword from its scabbard, Minerva came down from heaven
+(for Juno had sent her in the love she bore to them both), and
+seized the son of Peleus by his yellow hair, visible to him
+alone, for of the others no man could see her. Achilles turned in
+amaze, and by the fire that flashed from her eyes at once knew
+that she was Minerva. "Why are you here," said he, "daughter of
+aegis-bearing Jove? To see the pride of Agamemnon, son of Atreus?
+Let me tell you--and it shall surely be--he shall pay for this
+insolence with his life."
+</para>
+
+<para>
+And Minerva said, "I come from heaven, if you will hear me, to
+bid you stay your anger. Juno has sent me, who cares for both of
+you alike. Cease, then, this brawling, and do not draw your
+sword; rail at him if you will, and your railing will not be
+vain, for I tell you--and it shall surely be--that you shall
+hereafter receive gifts three times as splendid by reason of this
+present insult. Hold, therefore, and obey."
+</para>
+
+<para>
+"Goddess," answered Achilles, "however angry a man may be, he
+must do as you two command him. This will be best, for the gods
+ever hear the prayers of him who has obeyed them."
+</para>
+
+<para>
+He stayed his hand on the silver hilt of his sword, and thrust it
+back into the scabbard as Minerva bade him. Then she went back to
+Olympus among the other gods, and to the house of aegis-bearing
+Jove.
+</para>
+
+<para>
+But the son of Peleus again began railing at the son of Atreus,
+for he was still in a rage. "Wine-bibber," he cried, "with the
+face of a dog and the heart of a hind, you never dare to go out
+with the host in fight, nor yet with our chosen men in ambuscade.
+You shun this as you do death itself. You had rather go round and
+rob his prizes from any man who contradicts you. You devour your
+people, for you are king over a feeble folk; otherwise, son of
+Atreus, henceforward you would insult no man. Therefore I say,
+and swear it with a great oath--nay, by this my sceptre which
+shalt sprout neither leaf nor shoot, nor bud anew from the day on
+which it left its parent stem upon the mountains--for the axe
+stripped it of leaf and bark, and now the sons of the Achaeans
+bear it as judges and guardians of the decrees of heaven--so
+surely and solemnly do I swear that hereafter they shall look
+fondly for Achilles and shall not find him. In the day of your
+distress, when your men fall dying by the murderous hand of
+Hector, you shall not know how to help them, and shall rend your
+heart with rage for the hour when you offered insult to the
+bravest of the Achaeans."
+</para>
+
+<para>
+With this the son of Peleus dashed his gold-bestudded sceptre on
+the ground and took his seat, while the son of Atreus was
+beginning fiercely from his place upon the other side. Then
+uprose smooth-tongued Nestor, the facile speaker of the Pylians,
+and the words fell from his lips sweeter than honey. Two
+generations of men born and bred in Pylos had passed away under
+his rule, and he was now reigning over the third. With all
+sincerity and goodwill, therefore, he addressed them thus:--
+</para>
+
+<para>
+"Of a truth," he said, "a great sorrow has befallen the Achaean
+land. Surely Priam with his sons would rejoice, and the Trojans
+be glad at heart if they could hear this quarrel between you two,
+who are so excellent in fight and counsel. I am older than either
+of you; therefore be guided by me. Moreover I have been the
+familiar friend of men even greater than you are, and they did
+not disregard my counsels. Never again can I behold such men as
+Pirithous and Dryas shepherd of his people, or as Caeneus,
+Exadius, godlike Polyphemus, and Theseus son of Aegeus, peer of
+the immortals. These were the mightiest men ever born upon this
+earth: mightiest were they, and when they fought the fiercest
+tribes of mountain savages they utterly overthrew them. I came
+from distant Pylos, and went about among them, for they would
+have me come, and I fought as it was in me to do. Not a man now
+living could withstand them, but they heard my words, and were
+persuaded by them. So be it also with yourselves, for this is the
+more excellent way. Therefore, Agamemnon, though you be strong,
+take not this girl away, for the sons of the Achaeans have
+already given her to Achilles; and you, Achilles, strive not
+further with the king, for no man who by the grace of Jove wields
+a sceptre has like honour with Agamemnon. You are strong, and
+have a goddess for your mother; but Agamemnon is stronger than
+you, for he has more people under him. Son of Atreus, check your
+anger, I implore you; end this quarrel with Achilles, who in the
+day of battle is a tower of strength to the Achaeans."
+</para>
+
+<para>
+And Agamemnon answered, "Sir, all that you have said is true, but
+this fellow must needs become our lord and master: he must be
+lord of all, king of all, and captain of all, and this shall
+hardly be. Granted that the gods have made him a great warrior,
+have they also given him the right to speak with railing?"
+</para>
+
+<para>
+Achilles interrupted him. "I should be a mean coward," he cried,
+"were I to give in to you in all things. Order other people
+about, not me, for I shall obey no longer. Furthermore I say--and
+lay my saying to your heart--I shall fight neither you nor any
+man about this girl, for those that take were those also that
+gave. But of all else that is at my ship you shall carry away
+nothing by force. Try, that others may see; if you do, my spear
+shall be reddened with your blood."
+</para>
+
+<para>
+When they had quarrelled thus angrily, they rose, and broke up
+the assembly at the ships of the Achaeans. The son of Peleus went
+back to his tents and ships with the son of Menoetius and his
+company, while Agamemnon drew a vessel into the water and chose a
+crew of twenty oarsmen. He escorted Chryseis on board and sent
+moreover a hecatomb for the god. And Ulysses went as captain.
+</para>
+
+<para>
+These, then, went on board and sailed their ways over the sea.
+But the son of Atreus bade the people purify themselves; so they
+purified themselves and cast their filth into the sea. Then they
+offered hecatombs of bulls and goats without blemish on the
+sea-shore, and the smoke with the savour of their sacrifice rose
+curling up towards heaven.
+</para>
+
+<para>
+Thus did they busy themselves throughout the host. But Agamemnon
+did not forget the threat that he had made Achilles, and called
+his trusty messengers and squires Talthybius and Eurybates. "Go,"
+said he, "to the tent of Achilles, son of Peleus; take Briseis by
+the hand and bring her hither; if he will not give her I shall
+come with others and take her--which will press him harder."
+</para>
+
+<para>
+He charged them straightly further and dismissed them, whereon
+they went their way sorrowfully by the seaside, till they came to
+the tents and ships of the Myrmidons. They found Achilles sitting
+by his tent and his ships, and ill-pleased he was when he beheld
+them. They stood fearfully and reverently before him, and never a
+word did they speak, but he knew them and said, "Welcome,
+heralds, messengers of gods and men; draw near; my quarrel is not
+with you but with Agamemnon who has sent you for the girl
+Briseis. Therefore, Patroclus, bring her and give her to them,
+but let them be witnesses by the blessed gods, by mortal men, and
+by the fierceness of Agamemnon's anger, that if ever again there
+be need of me to save the people from ruin, they shall seek and
+they shall not find. Agamemnon is mad with rage and knows not how
+to look before and after that the Achaeans may fight by their
+ships in safety."
+</para>
+
+<para>
+Patroclus did as his dear comrade had bidden him. He brought
+Briseis from the tent and gave her over to the heralds, who took
+her with them to the ships of the Achaeans--and the woman was
+loth to go. Then Achilles went all alone by the side of the hoar
+sea, weeping and looking out upon the boundless waste of waters.
+He raised his hands in prayer to his immortal mother, "Mother,"
+he cried, "you bore me doomed to live but for a little season;
+surely Jove, who thunders from Olympus, might have made that
+little glorious. It is not so. Agamemnon, son of Atreus, has done
+me dishonour, and has robbed me of my prize by force."
+</para>
+
+<para>
+As he spoke he wept aloud, and his mother heard him where she was
+sitting in the depths of the sea hard by the old man her father.
+Forthwith she rose as it were a grey mist out of the waves, sat
+down before him as he stood weeping, caressed him with her hand,
+and said, "My son, why are you weeping? What is it that grieves
+you? Keep it not from me, but tell me, that we may know it
+together."
+</para>
+
+<para>
+Achilles drew a deep sigh and said, "You know it; why tell you
+what you know well already? We went to Thebe the strong city of
+Eetion, sacked it, and brought hither the spoil. The sons of the
+Achaeans shared it duly among themselves, and chose lovely
+Chryseis as the meed of Agamemnon; but Chryses, priest of Apollo,
+came to the ships of the Achaeans to free his daughter, and
+brought with him a great ransom: moreover he bore in his hand the
+sceptre of Apollo, wreathed with a suppliant's wreath, and he
+besought the Achaeans, but most of all the two sons of Atreus who
+were their chiefs.
+</para>
+
+<para>
+"On this the rest of the Achaeans with one voice were for
+respecting the priest and taking the ransom that he offered; but
+not so Agamemnon, who spoke fiercely to him and sent him roughly
+away. So he went back in anger, and Apollo, who loved him dearly,
+heard his prayer. Then the god sent a deadly dart upon the
+Argives, and the people died thick on one another, for the arrows
+went everywhither among the wide host of the Achaeans. At last a
+seer in the fulness of his knowledge declared to us the oracles
+of Apollo, and I was myself first to say that we should appease
+him. Whereon the son of Atreus rose in anger, and threatened that
+which he has since done. The Achaeans are now taking the girl in
+a ship to Chryse, and sending gifts of sacrifice to the god; but
+the heralds have just taken from my tent the daughter of Briseus,
+whom the Achaeans had awarded to myself.
+</para>
+
+<para>
+"Help your brave son, therefore, if you are able. Go to Olympus,
+and if you have ever done him service in word or deed, implore
+the aid of Jove. Ofttimes in my father's house have I heard you
+glory in that you alone of the immortals saved the son of Saturn
+from ruin, when the others, with Juno, Neptune, and Pallas
+Minerva would have put him in bonds. It was you, goddess, who
+delivered him by calling to Olympus the hundred-handed monster
+whom gods call Briareus, but men Aegaeon, for he is stronger even
+than his father; when therefore he took his seat all-glorious
+beside the son of Saturn, the other gods were afraid, and did not
+bind him. Go, then, to him, remind him of all this, clasp his
+knees, and bid him give succour to the Trojans. Let the Achaeans
+be hemmed in at the sterns of their ships, and perish on the
+sea-shore, that they may reap what joy they may of their king,
+and that Agamemnon may rue his blindness in offering insult to
+the foremost of the Achaeans."
+</para>
+
+<para>
+Thetis wept and answered, "My son, woe is me that I should have
+borne or suckled you. Would indeed that you had lived your span
+free from all sorrow at your ships, for it is all too brief;
+alas, that you should be at once short of life and long of sorrow
+above your peers: woe, therefore, was the hour in which I bore
+you; nevertheless I will go to the snowy heights of Olympus, and
+tell this tale to Jove, if he will hear our prayer: meanwhile
+stay where you are with your ships, nurse your anger against the
+Achaeans, and hold aloof from fight. For Jove went yesterday to
+Oceanus, to a feast among the Ethiopians, and the other gods went
+with him. He will return to Olympus twelve days hence; I will
+then go to his mansion paved with bronze and will beseech him;
+nor do I doubt that I shall be able to persuade him."
+</para>
+
+<para>
+On this she left him, still furious at the loss of her that had
+been taken from him. Meanwhile Ulysses reached Chryse with the
+hecatomb. When they had come inside the harbour they furled the
+sails and laid them in the ship's hold; they slackened the
+forestays, lowered the mast into its place, and rowed the ship to
+the place where they would have her lie; there they cast out
+their mooring-stones and made fast the hawsers. They then got out
+upon the sea-shore and landed the hecatomb for Apollo; Chryseis
+also left the ship, and Ulysses led her to the altar to deliver
+her into the hands of her father. "Chryses," said he, "King
+Agamemnon has sent me to bring you back your child, and to offer
+sacrifice to Apollo on behalf of the Danaans, that we may
+propitiate the god, who has now brought sorrow upon the Argives."
+</para>
+
+<para>
+So saying he gave the girl over to her father, who received her
+gladly, and they ranged the holy hecatomb all orderly round the
+altar of the god. They washed their hands and took up the
+barley-meal to sprinkle over the victims, while Chryses lifted up
+his hands and prayed aloud on their behalf. "Hear me," he cried,
+"O god of the silver bow, that protectest Chryse and holy Cilla,
+and rulest Tenedos with thy might. Even as thou didst hear me
+aforetime when I prayed, and didst press hardly upon the
+Achaeans, so hear me yet again, and stay this fearful pestilence
+from the Danaans."
+</para>
+
+<para>
+Thus did he pray, and Apollo heard his prayer. When they had done
+praying and sprinkling the barley-meal, they drew back the heads
+of the victims and killed and flayed them. They cut out the
+thigh-bones, wrapped them round in two layers of fat, set some
+pieces of raw meat on the top of them, and then Chryses laid them
+on the wood fire and poured wine over them, while the young men
+stood near him with five-pronged spits in their hands. When the
+thigh-bones were burned and they had tasted the inward meats,
+they cut the rest up small, put the pieces upon the spits,
+roasted them till they were done, and drew them off: then, when
+they had finished their work and the feast was ready, they ate
+it, and every man had his full share, so that all were satisfied.
+As soon as they had had enough to eat and drink, pages filled the
+mixing-bowl with wine and water and handed it round, after giving
+every man his drink-offering.
+</para>
+
+<para>
+Thus all day long the young men worshipped the god with song,
+hymning him and chaunting the joyous paean, and the god took
+pleasure in their voices; but when the sun went down, and it came
+on dark, they laid themselves down to sleep by the stern cables
+of the ship, and when the child of morning, rosy-fingered Dawn,
+appeared they again set sail for the host of the Achaeans. Apollo
+sent them a fair wind, so they raised their mast and hoisted
+their white sails aloft. As the sail bellied with the wind the
+ship flew through the deep blue water, and the foam hissed
+against her bows as she sped onward. When they reached the
+wide-stretching host of the Achaeans, they drew the vessel
+ashore, high and dry upon the sands, set her strong props beneath
+her, and went their ways to their own tents and ships.
+</para>
+
+<para>
+But Achilles abode at his ships and nursed his anger. He went not
+to the honourable assembly, and sallied not forth to fight, but
+gnawed at his own heart, pining for battle and the war-cry.
+</para>
+
+<para>
+Now after twelve days the immortal gods came back in a body to
+Olympus, and Jove led the way. Thetis was not unmindful of the
+charge her son had laid upon her, so she rose from under the sea
+and went through great heaven with early morning to Olympus,
+where she found the mighty son of Saturn sitting all alone upon
+its topmost ridges. She sat herself down before him, and with her
+left hand seized his knees, while with her right she caught him
+under the chin, and besought him, saying:--
+</para>
+
+<para>
+"Father Jove, if I ever did you service in word or deed among the
+immortals, hear my prayer, and do honour to my son, whose life is
+to be cut short so early. King Agamemnon has dishonoured him by
+taking his prize and keeping her. Honour him then yourself,
+Olympian lord of counsel, and grant victory to the Trojans, till
+the Achaeans give my son his due and load him with riches in
+requital."
+</para>
+
+<para>
+Jove sat for a while silent, and without a word, but Thetis still
+kept firm hold of his knees, and besought him a second time.
+"Incline your head," said she, "and promise me surely, or else
+deny me--for you have nothing to fear--that I may learn how
+greatly you disdain me."
+</para>
+
+<para>
+At this Jove was much troubled and answered, "I shall have
+trouble if you set me quarrelling with Juno, for she will provoke
+me with her taunting speeches; even now she is always railing at
+me before the other gods and accusing me of giving aid to the
+Trojans. Go back now, lest she should find out. I will consider
+the matter, and will bring it about as you wish. See, I incline
+my head that you may believe me. This is the most solemn promise
+that I can give to any god. I never recall my word, or deceive,
+or fail to do what I say, when I have nodded my head."
+</para>
+
+<para>
+As he spoke the son of Saturn bowed his dark brows, and the
+ambrosial locks swayed on his immortal head, till vast Olympus
+reeled.
+</para>
+
+<para>
+When the pair had thus laid their plans, they parted--Jove to his
+house, while the goddess quitted the splendour of Olympus, and
+plunged into the depths of the sea. The gods rose from their
+seats, before the coming of their sire. Not one of them dared to
+remain sitting, but all stood up as he came among them. There,
+then, he took his seat. But Juno, when she saw him, knew that he
+and the old merman's daughter, silver-footed Thetis, had been
+hatching mischief, so she at once began to upbraid him.
+"Trickster," she cried, "which of the gods have you been taking
+into your counsels now? You are always settling matters in secret
+behind my back, and have never yet told me, if you could help it,
+one word of your intentions."
+</para>
+
+<para>
+"Juno," replied the sire of gods and men, "you must not expect to
+be informed of all my counsels. You are my wife, but you would
+find it hard to understand them. When it is proper for you to
+hear, there is no one, god or man, who will be told sooner, but
+when I mean to keep a matter to myself, you must not pry nor ask
+questions."
+</para>
+
+<para>
+"Dread son of Saturn," answered Juno, "what are you talking
+about? I? Pry and ask questions? Never. I let you have your own
+way in everything. Still, I have a strong misgiving that the old
+merman's daughter Thetis has been talking you over, for she was
+with you and had hold of your knees this self-same morning. I
+believe, therefore, that you have been promising her to give
+glory to Achilles, and to kill much people at the ships of the
+Achaeans."
+</para>
+
+<para>
+"Wife," said Jove, "I can do nothing but you suspect me and find
+it out. You will take nothing by it, for I shall only dislike you
+the more, and it will go harder with you. Granted that it is as
+you say; I mean to have it so; sit down and hold your tongue as I
+bid you for if I once begin to lay my hands about you, though all
+heaven were on your side it would profit you nothing."
+</para>
+
+<para>
+On this Juno was frightened, so she curbed her stubborn will and
+sat down in silence. But the heavenly beings were disquieted
+throughout the house of Jove, till the cunning workman Vulcan
+began to try and pacify his mother Juno. "It will be
+intolerable," said he, "if you two fall to wrangling and setting
+heaven in an uproar about a pack of mortals. If such ill counsels
+are to prevail, we shall have no pleasure at our banquet. Let me
+then advise my mother--and she must herself know that it will be
+better--to make friends with my dear father Jove, lest he again
+scold her and disturb our feast. If the Olympian Thunderer wants
+to hurl us all from our seats, he can do so, for he is far the
+strongest, so give him fair words, and he will then soon be in a
+good humour with us."
+</para>
+
+<para>
+As he spoke, he took a double cup of nectar, and placed it in his
+mother's hand. "Cheer up, my dear mother," said he, "and make the
+best of it. I love you dearly, and should be very sorry to see
+you get a thrashing; however grieved I might be, I could not help,
+for there is no standing against Jove. Once before when I was
+trying to help you, he caught me by the foot and flung me from
+the heavenly threshold. All day long from morn till eve, was I
+falling, till at sunset I came to ground in the island of Lemnos,
+and there I lay, with very little life left in me, till the
+Sintians came and tended me."
+</para>
+
+<para>
+Juno smiled at this, and as she smiled she took the cup from her
+son's hands. Then Vulcan drew sweet nectar from the mixing-bowl,
+and served it round among the gods, going from left to right; and
+the blessed gods laughed out a loud applause as they saw him
+bustling about the heavenly mansion.
+</para>
+
+<para>
+Thus through the livelong day to the going down of the sun they
+feasted, and every one had his full share, so that all were
+satisfied. Apollo struck his lyre, and the Muses lifted up their
+sweet voices, calling and answering one another. But when the
+sun's glorious light had faded, they went home to bed, each in
+his own abode, which lame Vulcan with his consummate skill had
+fashioned for them. So Jove, the Olympian Lord of Thunder, hied
+him to the bed in which he always slept; and when he had got on
+to it he went to sleep, with Juno of the golden throne by his
+side.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK II</title>
+
+<para>
+Now the other gods and the armed warriors on the plain slept
+soundly, but Jove was wakeful, for he was thinking how to do
+honour to Achilles, and destroyed much people at the ships of the
+Achaeans. In the end he deemed it would be best to send a lying
+dream to King Agamemnon; so he called one to him and said to it,
+"Lying Dream, go to the ships of the Achaeans, into the tent of
+Agamemnon, and say to him word for word as I now bid you. Tell
+him to get the Achaeans instantly under arms, for he shall take
+Troy. There are no longer divided counsels among the gods; Juno
+has brought them to her own mind, and woe betides the Trojans."
+</para>
+
+<para>
+The dream went when it had heard its message, and soon reached
+the ships of the Achaeans. It sought Agamemnon son of Atreus and
+found him in his tent, wrapped in a profound slumber. It hovered
+over his head in the likeness of Nestor, son of Neleus, whom
+Agamemnon honoured above all his councillors, and said:--
+</para>
+
+<para>
+"You are sleeping, son of Atreus; one who has the welfare of his
+host and so much other care upon his shoulders should dock his
+sleep. Hear me at once, for I come as a messenger from Jove, who,
+though he be not near, yet takes thought for you and pities you.
+He bids you get the Achaeans instantly under arms, for you shall
+take Troy. There are no longer divided counsels among the gods;
+Juno has brought them over to her own mind, and woe betides the
+Trojans at the hands of Jove. Remember this, and when you wake
+see that it does not escape you."
+</para>
+
+<para>
+The dream then left him, and he thought of things that were,
+surely not to be accomplished. He thought that on that same day
+he was to take the city of Priam, but he little knew what was in
+the mind of Jove, who had many another hard-fought fight in store
+alike for Danaans and Trojans. Then presently he woke, with the
+divine message still ringing in his ears; so he sat upright, and
+put on his soft shirt so fair and new, and over this his heavy
+cloak. He bound his sandals on to his comely feet, and slung his
+silver-studded sword about his shoulders; then he took the
+imperishable staff of his father, and sallied forth to the ships
+of the Achaeans.
+</para>
+
+<para>
+The goddess Dawn now wended her way to vast Olympus that she
+might herald day to Jove and to the other immortals, and
+Agamemnon sent the criers round to call the people in assembly;
+so they called them and the people gathered thereon. But first he
+summoned a meeting of the elders at the ship of Nestor king of
+Pylos, and when they were assembled he laid a cunning counsel
+before them.
+</para>
+
+<para>
+"My friends," said he, "I have had a dream from heaven in the
+dead of night, and its face and figure resembled none but
+Nestor's. It hovered over my head and said, 'You are sleeping,
+son of Atreus; one who has the welfare of his host and so much
+other care upon his shoulders should dock his sleep. Hear me at
+once, for I am a messenger from Jove, who, though he be not near,
+yet takes thought for you and pities you. He bids you get the
+Achaeans instantly under arms, for you shall take Troy. There are
+no longer divided counsels among the gods; Juno has brought them
+over to her own mind, and woe betides the Trojans at the hands of
+Jove. Remember this.' The dream then vanished and I awoke. Let us
+now, therefore, arm the sons of the Achaeans. But it will be well
+that I should first sound them, and to this end I will tell them
+to fly with their ships; but do you others go about among the
+host and prevent their doing so."
+</para>
+
+<para>
+He then sat down, and Nestor the prince of Pylos with all
+sincerity and goodwill addressed them thus: "My friends," said
+he, "princes and councillors of the Argives, if any other man of
+the Achaeans had told us of this dream we should have declared it
+false, and would have had nothing to do with it. But he who has
+seen it is the foremost man among us; we must therefore set about
+getting the people under arms."
+</para>
+
+<para>
+With this he led the way from the assembly, and the other
+sceptred kings rose with him in obedience to the word of
+Agamemnon; but the people pressed forward to hear. They swarmed
+like bees that sally from some hollow cave and flit in countless
+throng among the spring flowers, bunched in knots and clusters;
+even so did the mighty multitude pour from ships and tents to the
+assembly, and range themselves upon the wide-watered shore, while
+among them ran Wildfire Rumour, messenger of Jove, urging them
+ever to the fore. Thus they gathered in a pell-mell of mad
+confusion, and the earth groaned under the tramp of men as the
+people sought their places. Nine heralds went crying about among
+them to stay their tumult and bid them listen to the kings, till
+at last they were got into their several places and ceased their
+clamour. Then King Agamemnon rose, holding his sceptre. This was
+the work of Vulcan, who gave it to Jove the son of Saturn. Jove
+gave it to Mercury, slayer of Argus, guide and guardian. King
+Mercury gave it to Pelops, the mighty charioteer, and Pelops to
+Atreus, shepherd of his people. Atreus, when he died, left it to
+Thyestes, rich in flocks, and Thyestes in his turn left it to be
+borne by Agamemnon, that he might be lord of all Argos and of the
+isles. Leaning, then, on his sceptre, he addressed the Argives.
+</para>
+
+<para>
+"My friends," he said, "heroes, servants of Mars, the hand of
+heaven has been laid heavily upon me. Cruel Jove gave me his
+solemn promise that I should sack the city of Priam before
+returning, but he has played me false, and is now bidding me go
+ingloriously back to Argos with the loss of much people. Such is
+the will of Jove, who has laid many a proud city in the dust, as
+he will yet lay others, for his power is above all. It will be a
+sorry tale hereafter that an Achaean host, at once so great and
+valiant, battled in vain against men fewer in number than
+themselves; but as yet the end is not in sight. Think that the
+Achaeans and Trojans have sworn to a solemn covenant, and that
+they have each been numbered--the Trojans by the roll of their
+householders, and we by companies of ten; think further that each
+of our companies desired to have a Trojan householder to pour out
+their wine; we are so greatly more in number that full many a
+company would have to go without its cup-bearer. But they have in
+the town allies from other places, and it is these that hinder me
+from being able to sack the rich city of Ilius. Nine of Jove's
+years are gone; the timbers of our ships have rotted; their
+tackling is sound no longer. Our wives and little ones at home
+look anxiously for our coming, but the work that we came hither
+to do has not been done. Now, therefore, let us all do as I say:
+let us sail back to our own land, for we shall not take Troy."
+</para>
+
+<para>
+With these words he moved the hearts of the multitude, so many of
+them as knew not the cunning counsel of Agamemnon. They surged to
+and fro like the waves of the Icarian Sea, when the east and
+south winds break from heaven's clouds to lash them; or as when
+the west wind sweeps over a field of corn and the ears bow
+beneath the blast, even so were they swayed as they flew with
+loud cries towards the ships, and the dust from under their feet
+rose heavenward. They cheered each other on to draw the ships
+into the sea; they cleared the channels in front of them; they
+began taking away the stays from underneath them, and the welkin
+rang with their glad cries, so eager were they to return.
+</para>
+
+<para>
+Then surely the Argives would have returned after a fashion that
+was not fated. But Juno said to Minerva, "Alas, daughter of
+aegis-bearing Jove, unweariable, shall the Argives fly home to
+their own land over the broad sea, and leave Priam and the
+Trojans the glory of still keeping Helen, for whose sake so many
+of the Achaeans have died at Troy, far from their homes? Go about
+at once among the host, and speak fairly to them, man by man,
+that they draw not their ships into the sea."
+</para>
+
+<para>
+Minerva was not slack to do her bidding. Down she darted from the
+topmost summits of Olympus, and in a moment she was at the ships
+of the Achaeans. There she found Ulysses, peer of Jove in
+counsel, standing alone. He had not as yet laid a hand upon his
+ship, for he was grieved and sorry; so she went close up to him
+and said, "Ulysses, noble son of Laertes, are you going to fling
+yourselves into your ships and be off home to your own land in
+this way? Will you leave Priam and the Trojans the glory of still
+keeping Helen, for whose sake so many of the Achaeans have died
+at Troy, far from their homes? Go about at once among the host,
+and speak fairly to them, man by man, that they draw not their
+ships into the sea."
+</para>
+
+<para>
+Ulysses knew the voice as that of the goddess: he flung his cloak
+from him and set off to run. His servant Eurybates, a man of
+Ithaca, who waited on him, took charge of the cloak, whereon
+Ulysses went straight up to Agamemnon and received from him his
+ancestral, imperishable staff. With this he went about among the
+ships of the Achaeans.
+</para>
+
+<para>
+Whenever he met a king or chieftain, he stood by him and spoke
+him fairly. "Sir," said he, "this flight is cowardly and
+unworthy. Stand to your post, and bid your people also keep their
+places. You do not yet know the full mind of Agamemnon; he was
+sounding us, and ere long will visit the Achaeans with his
+displeasure. We were not all of us at the council to hear what he
+then said; see to it lest he be angry and do us a mischief; for
+the pride of kings is great, and the hand of Jove is with them."
+</para>
+
+<para>
+But when he came across any common man who was making a noise, he
+struck him with his staff and rebuked him, saying, "Sirrah, hold
+your peace, and listen to better men than yourself. You are a
+coward and no soldier; you are nobody either in fight or council;
+we cannot all be kings; it is not well that there should be many
+masters; one man must be supreme--one king to whom the son of
+scheming Saturn has given the sceptre of sovereignty over you
+all."
+</para>
+
+<para>
+Thus masterfully did he go about among the host, and the people
+hurried back to the council from their tents and ships with a
+sound as the thunder of surf when it comes crashing down upon the
+shore, and all the sea is in an uproar.
+</para>
+
+<para>
+The rest now took their seats and kept to their own several
+places, but Thersites still went on wagging his unbridled
+tongue--a man of many words, and those unseemly; a monger of
+sedition, a railer against all who were in authority, who cared
+not what he said, so that he might set the Achaeans in a laugh.
+He was the ugliest man of all those that came before
+Troy--bandy-legged, lame of one foot, with his two shoulders
+rounded and hunched over his chest. His head ran up to a point,
+but there was little hair on the top of it. Achilles and Ulysses
+hated him worst of all, for it was with them that he was most
+wont to wrangle; now, however, with a shrill squeaky voice he
+began heaping his abuse on Agamemnon. The Achaeans were angry and
+disgusted, yet none the less he kept on brawling and bawling at
+the son of Atreus.
+</para>
+
+<para>
+"Agamemnon," he cried, "what ails you now, and what more do you
+want? Your tents are filled with bronze and with fair women, for
+whenever we take a town we give you the pick of them. Would you
+have yet more gold, which some Trojan is to give you as a ransom
+for his son, when I or another Achaean has taken him prisoner? or
+is it some young girl to hide and lie with? It is not well that
+you, the ruler of the Achaeans, should bring them into such
+misery. Weakling cowards, women rather than men, let us sail
+home, and leave this fellow here at Troy to stew in his own meeds
+of honour, and discover whether we were of any service to him or
+no. Achilles is a much better man than he is, and see how he has
+treated him--robbing him of his prize and keeping it himself.
+Achilles takes it meekly and shows no fight; if he did, son of
+Atreus, you would never again insult him."
+</para>
+
+<para>
+Thus railed Thersites, but Ulysses at once went up to him and
+rebuked him sternly. "Check your glib tongue, Thersites," said
+be, "and babble not a word further. Chide not with princes when
+you have none to back you. There is no viler creature come before
+Troy with the sons of Atreus. Drop this chatter about kings, and
+neither revile them nor keep harping about going home. We do not
+yet know how things are going to be, nor whether the Achaeans are
+to return with good success or evil. How dare you gibe at
+Agamemnon because the Danaans have awarded him so many prizes? I
+tell you, therefore--and it shall surely be--that if I again
+catch you talking such nonsense, I will either forfeit my own
+head and be no more called father of Telemachus, or I will take
+you, strip you stark naked, and whip you out of the assembly till
+you go blubbering back to the ships."
+</para>
+
+<para>
+On this he beat him with his staff about the back and shoulders
+till he dropped and fell a-weeping. The golden sceptre raised a
+bloody weal on his back, so he sat down frightened and in pain,
+looking foolish as he wiped the tears from his eyes. The people
+were sorry for him, yet they laughed heartily, and one would turn
+to his neighbour saying, "Ulysses has done many a good thing ere
+now in fight and council, but he never did the Argives a better
+turn than when he stopped this fellow's mouth from prating
+further. He will give the kings no more of his insolence."
+</para>
+
+<para>
+Thus said the people. Then Ulysses rose, sceptre in hand, and
+Minerva in the likeness of a herald bade the people be still,
+that those who were far off might hear him and consider his
+council. He therefore with all sincerity and goodwill addressed
+them thus:--
+</para>
+
+<para>
+"King Agamemnon, the Achaeans are for making you a by-word among
+all mankind. They forget the promise they made you when they set
+out from Argos, that you should not return till you had sacked
+the town of Troy, and, like children or widowed women, they
+murmur and would set off homeward. True it is that they have had
+toil enough to be disheartened. A man chafes at having to stay
+away from his wife even for a single month, when he is on
+shipboard, at the mercy of wind and sea, but it is now nine long
+years that we have been kept here; I cannot, therefore, blame the
+Achaeans if they turn restive; still we shall be shamed if we go
+home empty after so long a stay--therefore, my friends, be
+patient yet a little longer that we may learn whether the
+prophesyings of Calchas were false or true.
+</para>
+
+<para>
+"All who have not since perished must remember as though it were
+yesterday or the day before, how the ships of the Achaeans were
+detained in Aulis when we were on our way hither to make war on
+Priam and the Trojans. We were ranged round about a fountain
+offering hecatombs to the gods upon their holy altars, and there
+was a fine plane-tree from beneath which there welled a stream of
+pure water. Then we saw a prodigy; for Jove sent a fearful
+serpent out of the ground, with blood-red stains upon its back,
+and it darted from under the altar on to the plane-tree. Now
+there was a brood of young sparrows, quite small, upon the
+topmost bough, peeping out from under the leaves, eight in all,
+and their mother that hatched them made nine. The serpent ate the
+poor cheeping things, while the old bird flew about lamenting her
+little ones; but the serpent threw his coils about her and caught
+her by the wing as she was screaming. Then, when he had eaten
+both the sparrow and her young, the god who had sent him made him
+become a sign; for the son of scheming Saturn turned him into
+stone, and we stood there wondering at that which had come to
+pass. Seeing, then, that such a fearful portent had broken in
+upon our hecatombs, Calchas forthwith declared to us the oracles
+of heaven. 'Why, Achaeans,' said he, 'are you thus speechless?
+Jove has sent us this sign, long in coming, and long ere it be
+fulfilled, though its fame shall last for ever. As the serpent
+ate the eight fledglings and the sparrow that hatched them, which
+makes nine, so shall we fight nine years at Troy, but in the
+tenth shall take the town.' This was what he said, and now it is
+all coming true. Stay here, therefore, all of you, till we take
+the city of Priam."
+</para>
+
+<para>
+On this the Argives raised a shout, till the ships rang again
+with the uproar. Nestor, knight of Gerene, then addressed them.
+"Shame on you," he cried, "to stay talking here like children,
+when you should fight like men. Where are our covenants now, and
+where the oaths that we have taken? Shall our counsels be flung
+into the fire, with our drink-offerings and the right hands of
+fellowship wherein we have put our trust? We waste our time in
+words, and for all our talking here shall be no further forward.
+Stand, therefore, son of Atreus, by your own steadfast purpose;
+lead the Argives on to battle, and leave this handful of men to
+rot, who scheme, and scheme in vain, to get back to Argos ere
+they have learned whether Jove be true or a liar. For the mighty
+son of Saturn surely promised that we should succeed, when we
+Argives set sail to bring death and destruction upon the Trojans.
+He showed us favourable signs by flashing his lightning on our
+right hands; therefore let none make haste to go till he has
+first lain with the wife of some Trojan, and avenged the toil and
+sorrow that he has suffered for the sake of Helen. Nevertheless,
+if any man is in such haste to be at home again, let him lay his
+hand to his ship that he may meet his doom in the sight of all.
+But, O king, consider and give ear to my counsel, for the word
+that I say may not be neglected lightly. Divide your men,
+Agamemnon, into their several tribes and clans, that clans and
+tribes may stand by and help one another. If you do this, and if
+the Achaeans obey you, you will find out who, both chiefs and
+peoples, are brave, and who are cowards; for they will vie
+against the other. Thus you shall also learn whether it is
+through the counsel of heaven or the cowardice of man that you
+shall fail to take the town."
+</para>
+
+<para>
+And Agamemnon answered, "Nestor, you have again outdone the sons
+of the Achaeans in counsel. Would, by Father Jove, Minerva, and
+Apollo, that I had among them ten more such councillors, for the
+city of King Priam would then soon fall beneath our hands, and we
+should sack it. But the son of Saturn afflicts me with bootless
+wranglings and strife. Achilles and I are quarrelling about this
+girl, in which matter I was the first to offend; if we can be of
+one mind again, the Trojans will not stave off destruction for a
+day. Now, therefore, get your morning meal, that our hosts join
+in fight. Whet well your spears; see well to the ordering of your
+shields; give good feeds to your horses, and look your chariots
+carefully over, that we may do battle the livelong day; for we
+shall have no rest, not for a moment, till night falls to part
+us. The bands that bear your shields shall be wet with the sweat
+upon your shoulders, your hands shall weary upon your spears,
+your horses shall steam in front of your chariots, and if I see
+any man shirking the fight, or trying to keep out of it at the
+ships, there shall be no help for him, but he shall be a prey to
+dogs and vultures."
+</para>
+
+<para>
+Thus he spoke, and the Achaeans roared applause. As when the
+waves run high before the blast of the south wind and break on
+some lofty headland, dashing against it and buffeting it without
+ceasing, as the storms from every quarter drive them, even so did
+the Achaeans rise and hurry in all directions to their ships.
+There they lighted their fires at their tents and got dinner,
+offering sacrifice every man to one or other of the gods, and
+praying each one of them that he might live to come out of the
+fight. Agamemnon, king of men, sacrificed a fat five-year-old
+bull to the mighty son of Saturn, and invited the princes and
+elders of his host. First he asked Nestor and King Idomeneus,
+then the two Ajaxes and the son of Tydeus, and sixthly Ulysses,
+peer of gods in counsel; but Menelaus came of his own accord, for
+he knew how busy his brother then was. They stood round the bull
+with the barley-meal in their hands, and Agamemnon prayed,
+saying, "Jove, most glorious, supreme, that dwellest in heaven,
+and ridest upon the storm-cloud, grant that the sun may not go
+down, nor the night fall, till the palace of Priam is laid low,
+and its gates are consumed with fire. Grant that my sword may
+pierce the shirt of Hector about his heart, and that full many of
+his comrades may bite the dust as they fall dying round him."
+</para>
+
+<para>
+Thus he prayed, but the son of Saturn would not fulfil his
+prayer. He accepted the sacrifice, yet none the less increased
+their toil continually. When they had done praying and sprinkling
+the barley-meal upon the victim, they drew back its head, killed
+it, and then flayed it. They cut out the thigh-bones, wrapped
+them round in two layers of fat, and set pieces of raw meat on
+the top of them. These they burned upon the split logs of
+firewood, but they spitted the inward meats, and held them in the
+flames to cook. When the thigh-bones were burned, and they had
+tasted the inward meats, they cut the rest up small, put the
+pieces upon spits, roasted them till they were done, and drew
+them off; then, when they had finished their work and the feast
+was ready, they ate it, and every man had his full share, so that
+all were satisfied. As soon as they had had enough to eat and
+drink, Nestor, knight of Gerene, began to speak. "King
+Agamemnon," said he, "let us not stay talking here, nor be slack
+in the work that heaven has put into our hands. Let the heralds
+summon the people to gather at their several ships; we will then
+go about among the host, that we may begin fighting at once."
+</para>
+
+<para>
+Thus did he speak, and Agamemnon heeded his words. He at once
+sent the criers round to call the people in assembly. So they
+called them, and the people gathered thereon. The chiefs about
+the son of Atreus chose their men and marshalled them, while
+Minerva went among them holding her priceless aegis that knows
+neither age nor death. From it there waved a hundred tassels of
+pure gold, all deftly woven, and each one of them worth a hundred
+oxen. With this she darted furiously everywhere among the hosts
+of the Achaeans, urging them forward, and putting courage into
+the heart of each, so that he might fight and do battle without
+ceasing. Thus war became sweeter in their eyes even than
+returning home in their ships. As when some great forest fire is
+raging upon a mountain top and its light is seen afar, even so as
+they marched the gleam of their armour flashed up into the
+firmament of heaven.
+</para>
+
+<para>
+They were like great flocks of geese, or cranes, or swans on the
+plain about the waters of Cayster, that wing their way hither and
+thither, glorying in the pride of flight, and crying as they
+settle till the fen is alive with their screaming. Even thus did
+their tribes pour from ships and tents on to the plain of the
+Scamander, and the ground rang as brass under the feet of men and
+horses. They stood as thick upon the flower-bespangled field as
+leaves that bloom in summer.
+</para>
+
+<para>
+As countless swarms of flies buzz around a herdsman's homestead
+in the time of spring when the pails are drenched with milk, even
+so did the Achaeans swarm on to the plain to charge the Trojans
+and destroy them.
+</para>
+
+<para>
+The chiefs disposed their men this way and that before the fight
+began, drafting them out as easily as goatherds draft their
+flocks when they have got mixed while feeding; and among them
+went King Agamemnon, with a head and face like Jove the lord of
+thunder, a waist like Mars, and a chest like that of Neptune. As
+some great bull that lords it over the herds upon the plain, even
+so did Jove make the son of Atreus stand peerless among the
+multitude of heroes.
+</para>
+
+<para>
+And now, O Muses, dwellers in the mansions of Olympus, tell me--
+for you are goddesses and are in all places so that you see all
+things, while we know nothing but by report--who were the chiefs
+and princes of the Danaans? As for the common soldiers, they were
+so that I could not name every single one of them though I had
+ten tongues, and though my voice failed not and my heart were of
+bronze within me, unless you, O Olympian Muses, daughters of
+aegis-bearing Jove, were to recount them to me. Nevertheless, I
+will tell the captains of the ships and all the fleet together.
+</para>
+
+<para>
+Peneleos, Leitus, Arcesilaus, Prothoenor, and Clonius were
+captains of the Boeotians. These were they that dwelt in Hyria
+and rocky Aulis, and who held Schoenus, Scolus, and the highlands
+of Eteonus, with Thespeia, Graia, and the fair city of
+Mycalessus. They also held Harma, Eilesium, and Erythrae; and
+they had Eleon, Hyle, and Peteon; Ocalea and the strong fortress
+of Medeon; Copae, Eutresis, and Thisbe the haunt of doves;
+Coronea, and the pastures of Haliartus; Plataea and Glisas; the
+fortress of Thebes the less; holy Onchestus with its famous grove
+of Neptune; Arne rich in vineyards; Midea, sacred Nisa, and
+Anthedon upon the sea. From these there came fifty ships, and in
+each there were a hundred and twenty young men of the Boeotians.
+</para>
+
+<para>
+Ascalaphus and Ialmenus, sons of Mars, led the people that dwelt
+in Aspledon and Orchomenus the realm of Minyas. Astyoche a noble
+maiden bore them in the house of Actor son of Azeus; for she had
+gone with Mars secretly into an upper chamber, and he had lain
+with her. With these there came thirty ships.
+</para>
+
+<para>
+The Phoceans were led by Schedius and Epistrophus, sons of mighty
+Iphitus the son of Naubolus. These were they that held
+Cyparissus, rocky Pytho, holy Crisa, Daulis, and Panopeus; they
+also that dwelt in Anemorea and Hyampolis, and about the waters
+of the river Cephissus, and Lilaea by the springs of the
+Cephissus; with their chieftains came forty ships, and they
+marshalled the forces of the Phoceans, which were stationed next
+to the Boeotians, on their left.
+</para>
+
+<para>
+Ajax, the fleet son of Oileus, commanded the Locrians. He was not
+so great, nor nearly so great, as Ajax the son of Telamon. He was
+a little man, and his breastplate was made of linen, but in use
+of the spear he excelled all the Hellenes and the Achaeans.
+These dwelt in Cynus, Opous, Calliarus, Bessa, Scarphe, fair
+Augeae, Tarphe, and Thronium about the river Boagrius. With him
+there came forty ships of the Locrians who dwell beyond Euboea.
+</para>
+
+<para>
+The fierce Abantes held Euboea with its cities, Chalcis, Eretria,
+Histiaea rich in vines, Cerinthus upon the sea, and the
+rock-perched town of Dium; with them were also the men of
+Carystus and Styra; Elephenor of the race of Mars was in command
+of these; he was son of Chalcodon, and chief over all the
+Abantes. With him they came, fleet of foot and wearing their hair
+long behind, brave warriors, who would ever strive to tear open
+the corslets of their foes with their long ashen spears. Of these
+there came fifty ships.
+</para>
+
+<para>
+And they that held the strong city of Athens, the people of great
+Erechtheus, who was born of the soil itself, but Jove's daughter,
+Minerva, fostered him, and established him at Athens in her own
+rich sanctuary. There, year by year, the Athenian youths worship
+him with sacrifices of bulls and rams. These were commanded by
+Menestheus, son of Peteos. No man living could equal him in the
+marshalling of chariots and foot soldiers. Nestor could alone
+rival him, for he was older. With him there came fifty ships.
+</para>
+
+<para>
+Ajax brought twelve ships from Salamis, and stationed them
+alongside those of the Athenians.
+</para>
+
+<para>
+The men of Argos, again, and those who held the walls of Tiryns,
+with Hermione, and Asine upon the gulf; Troezene, Eionae, and the
+vineyard lands of Epidaurus; the Achaean youths, moreover, who
+came from Aegina and Mases; these were led by Diomed of the loud
+battle-cry, and Sthenelus son of famed Capaneus. With them in
+command was Euryalus, son of king Mecisteus, son of Talaus; but
+Diomed was chief over them all. With these there came eighty
+ships.
+</para>
+
+<para>
+Those who held the strong city of Mycenae, rich Corinth and
+Cleonae; Orneae, Araethyrea, and Licyon, where Adrastus reigned
+of old; Hyperesia, high Gonoessa, and Pellene; Aegium and all the
+coast-land round about Helice; these sent a hundred ships under
+the command of King Agamemnon, son of Atreus. His force was far
+both finest and most numerous, and in their midst was the king
+himself, all glorious in his armour of gleaming bronze--foremost
+among the heroes, for he was the greatest king, and had most men
+under him.
+</para>
+
+<para>
+And those that dwelt in Lacedaemon, lying low among the hills,
+Pharis, Sparta, with Messe the haunt of doves; Bryseae, Augeae,
+Amyclae, and Helos upon the sea; Laas, moreover, and Oetylus;
+these were led by Menelaus of the loud battle-cry, brother to
+Agamemnon, and of them there were sixty ships, drawn up apart
+from the others. Among them went Menelaus himself, strong in
+zeal, urging his men to fight; for he longed to avenge the toil
+and sorrow that he had suffered for the sake of Helen.
+</para>
+
+<para>
+The men of Pylos and Arene, and Thryum where is the ford of the
+river Alpheus; strong Aipy, Cyparisseis, and Amphigenea; Pteleum,
+Helos, and Dorium, where the Muses met Thamyris, and stilled his
+minstrelsy for ever. He was returning from Oechalia, where
+Eurytus lived and reigned, and boasted that he would surpass even
+the Muses, daughters of aegis-bearing Jove, if they should sing
+against him; whereon they were angry, and maimed him. They robbed
+him of his divine power of song, and thenceforth he could strike
+the lyre no more. These were commanded by Nestor, knight of
+Gerene, and with him there came ninety ships.
+</para>
+
+<para>
+And those that held Arcadia, under the high mountain of Cyllene,
+near the tomb of Aepytus, where the people fight hand to hand;
+the men of Pheneus also, and Orchomenus rich in flocks; of
+Rhipae, Stratie, and bleak Enispe; of Tegea and fair Mantinea; of
+Stymphelus and Parrhasia; of these King Agapenor son of Ancaeus
+was commander, and they had sixty ships. Many Arcadians, good
+soldiers, came in each one of them, but Agamemnon found them the
+ships in which to cross the sea, for they were not a people that
+occupied their business upon the waters.
+</para>
+
+<para>
+The men, moreover, of Buprasium and of Elis, so much of it as is
+enclosed between Hyrmine, Myrsinus upon the sea-shore, the rock
+Olene and Alesium. These had four leaders, and each of them had
+ten ships, with many Epeans on board. Their captains were
+Amphimachus and Thalpius--the one, son of Cteatus, and the other,
+of Eurytus--both of the race of Actor. The two others were
+Diores, son of Amarynces, and Polyxenus, son of King Agasthenes,
+son of Augeas.
+</para>
+
+<para>
+And those of Dulichium with the sacred Echinean islands, who
+dwelt beyond the sea off Elis; these were led by Meges, peer of
+Mars, and the son of valiant Phyleus, dear to Jove, who
+quarrelled with his father, and went to settle in Dulichium. With
+him there came forty ships.
+</para>
+
+<para>
+Ulysses led the brave Cephallenians, who held Ithaca, Neritum
+with its forests, Crocylea, rugged Aegilips, Samos and Zacynthus,
+with the mainland also that was over against the islands. These
+were led by Ulysses, peer of Jove in counsel, and with him there
+came twelve ships.
+</para>
+
+<para>
+Thoas, son of Andraemon, commanded the Aetolians, who dwelt in
+Pleuron, Olenus, Pylene, Chalcis by the sea, and rocky Calydon,
+for the great king Oeneus had now no sons living, and was himself
+dead, as was also golden-haired Meleager, who had been set over
+the Aetolians to be their king. And with Thoas there came forty
+ships.
+</para>
+
+<para>
+The famous spearsman Idomeneus led the Cretans, who held Cnossus,
+and the well-walled city of Gortys; Lyctus also, Miletus and
+Lycastus that lies upon the chalk; the populous towns of Phaestus
+and Rhytium, with the other peoples that dwelt in the hundred
+cities of Crete. All these were led by Idomeneus, and by
+Meriones, peer of murderous Mars. And with these there came
+eighty ships.
+</para>
+
+<para>
+Tlepolemus, son of Hercules, a man both brave and large of
+stature, brought nine ships of lordly warriors from Rhodes. These
+dwelt in Rhodes which is divided among the three cities of
+Lindus, Ielysus, and Cameirus, that lies upon the chalk. These
+were commanded by Tlepolemus, son of Hercules by Astyochea, whom
+he had carried off from Ephyra, on the river Selleis, after
+sacking many cities of valiant warriors. When Tlepolemus grew up,
+he killed his father's uncle Licymnius, who had been a famous
+warrior in his time, but was then grown old. On this he built
+himself a fleet, gathered a great following, and fled beyond the
+sea, for he was menaced by the other sons and grandsons of
+Hercules. After a voyage, during which he suffered great
+hardship, he came to Rhodes, where the people divided into three
+communities, according to their tribes, and were dearly loved by
+Jove, the lord of gods and men; wherefore the son of Saturn
+showered down great riches upon them.
+</para>
+
+<para>
+And Nireus brought three ships from Syme--Nireus, who was the
+handsomest man that came up under Ilius of all the Danaans after
+the son of Peleus--but he was a man of no substance, and had but
+a small following.
+</para>
+
+<para>
+And those that held Nisyrus, Crapathus, and Casus, with Cos, the
+city of Eurypylus, and the Calydnian islands, these were
+commanded by Pheidippus and Antiphus, two sons of King Thessalus
+the son of Hercules. And with them there came thirty ships.
+</para>
+
+<para>
+Those again who held Pelasgic Argos, Alos, Alope, and Trachis;
+and those of Phthia and Hellas the land of fair women, who were
+called Myrmidons, Hellenes, and Achaeans; these had fifty ships,
+over which Achilles was in command. But they now took no part in
+the war, inasmuch as there was no one to marshal them; for
+Achilles stayed by his ships, furious about the loss of the girl
+Briseis, whom he had taken from Lyrnessus at his own great peril,
+when he had sacked Lyrnessus and Thebe, and had overthrown Mynes
+and Epistrophus, sons of king Evenor, son of Selepus. For her
+sake Achilles was still grieving, but ere long he was again to
+join them.
+</para>
+
+<para>
+And those that held Phylace and the flowery meadows of Pyrasus,
+sanctuary of Ceres; Iton, the mother of sheep; Antrum upon the
+sea, and Pteleum that lies upon the grass lands. Of these brave
+Protesilaus had been captain while he was yet alive, but he was
+now lying under the earth. He had left a wife behind him in
+Phylace to tear her cheeks in sorrow, and his house was only half
+finished, for he was slain by a Dardanian warrior while leaping
+foremost of the Achaeans upon the soil of Troy. Still, though his
+people mourned their chieftain, they were not without a leader,
+for Podarces, of the race of Mars, marshalled them; he was son of
+Iphiclus, rich in sheep, who was the son of Phylacus, and he was
+own brother to Protesilaus, only younger, Protesilaus being at
+once the elder and the more valiant. So the people were not
+without a leader, though they mourned him whom they had lost.
+With him there came forty ships.
+</para>
+
+<para>
+And those that held Pherae by the Boebean lake, with Boebe,
+Glaphyrae, and the populous city of Iolcus, these with their
+eleven ships were led by Eumelus, son of Admetus, whom Alcestis
+bore to him, loveliest of the daughters of Pelias.
+</para>
+
+<para>
+And those that held Methone and Thaumacia, with Meliboea and
+rugged Olizon, these were led by the skilful archer Philoctetes,
+and they had seven ships, each with fifty oarsmen all of them
+good archers; but Philoctetes was lying in great pain in the
+Island of Lemnos, where the sons of the Achaeans left him, for he
+had been bitten by a poisonous water snake. There he lay sick and
+sorry, and full soon did the Argives come to miss him. But his
+people, though they felt his loss were not leaderless, for Medon,
+the bastard son of Oileus by Rhene, set them in array.
+</para>
+
+<para>
+Those, again, of Tricca and the stony region of Ithome, and they
+that held Oechalia, the city of Oechalian Eurytus, these were
+commanded by the two sons of Aesculapius, skilled in the art of
+healing, Podalirius and Machaon. And with them there came thirty
+ships.
+</para>
+
+<para>
+The men, moreover, of Ormenius, and by the fountain of Hypereia,
+with those that held Asterius, and the white crests of Titanus,
+these were led by Eurypylus, the son of Euaemon, and with them
+there came forty ships.
+</para>
+
+<para>
+Those that held Argissa and Gyrtone, Orthe, Elone, and the white
+city of Oloosson, of these brave Polypoetes was leader. He was
+son of Pirithous, who was son of Jove himself, for Hippodameia
+bore him to Pirithous on the day when he took his revenge on the
+shaggy mountain savages and drove them from Mt. Pelion to the
+Aithices. But Polypoetes was not sole in command, for with him
+was Leonteus, of the race of Mars, who was son of Coronus, the
+son of Caeneus. And with these there came forty ships.
+</para>
+
+<para>
+Guneus brought two and twenty ships from Cyphus, and he was
+followed by the Enienes and the valiant Peraebi, who dwelt about
+wintry Dodona, and held the lands round the lovely river
+Titaresius, which sends its waters into the Peneus. They do not
+mingle with the silver eddies of the Peneus, but flow on the top
+of them like oil; for the Titaresius is a branch of dread Orcus
+and of the river Styx.
+</para>
+
+<para>
+Of the Magnetes, Prothous son of Tenthredon was commander. They
+were they that dwelt about the river Peneus and Mt. Pelion.
+Prothous, fleet of foot, was their leader, and with him there
+came forty ships.
+</para>
+
+<para>
+Such were the chiefs and princes of the Danaans. Who, then, O
+Muse, was the foremost, whether man or horse, among those that
+followed after the sons of Atreus?
+</para>
+
+<para>
+Of the horses, those of the son of Pheres were by far the finest.
+They were driven by Eumelus, and were as fleet as birds. They
+were of the same age and colour, and perfectly matched in height.
+Apollo, of the silver bow, had bred them in Perea--both of them
+mares, and terrible as Mars in battle. Of the men, Ajax, son of
+Telamon, was much the foremost so long as Achilles' anger lasted,
+for Achilles excelled him greatly and he had also better horses;
+but Achilles was now holding aloof at his ships by reason of his
+quarrel with Agamemnon, and his people passed their time upon the
+sea shore, throwing discs or aiming with spears at a mark, and in
+archery. Their horses stood each by his own chariot, champing
+lotus and wild celery. The chariots were housed under cover, but
+their owners, for lack of leadership, wandered hither and thither
+about the host and went not forth to fight.
+</para>
+
+<para>
+Thus marched the host like a consuming fire, and the earth
+groaned beneath them when the lord of thunder is angry and lashes
+the land about Typhoeus among the Arimi, where they say Typhoeus
+lies. Even so did the earth groan beneath them as they sped over
+the plain.
+</para>
+
+<para>
+And now Iris, fleet as the wind, was sent by Jove to tell the bad
+news among the Trojans. They were gathered in assembly, old and
+young, at Priam's gates, and Iris came close up to Priam,
+speaking with the voice of Priam's son Polites, who, being fleet
+of foot, was stationed as watchman for the Trojans on the tomb of
+old Aesyetes, to look out for any sally of the Achaeans. In his
+likeness Iris spoke, saying, "Old man, you talk idly, as in time
+of peace, while war is at hand. I have been in many a battle, but
+never yet saw such a host as is now advancing. They are crossing
+the plain to attack the city as thick as leaves or as the sands
+of the sea. Hector, I charge you above all others, do as I say.
+There are many allies dispersed about the city of Priam from
+distant places and speaking divers tongues. Therefore, let each
+chief give orders to his own people, setting them severally in
+array and leading them forth to battle."
+</para>
+
+<para>
+Thus she spoke, but Hector knew that it was the goddess, and at
+once broke up the assembly. The men flew to arms; all the gates
+were opened, and the people thronged through them, horse and
+foot, with the tramp as of a great multitude.
+</para>
+
+<para>
+Now there is a high mound before the city, rising by itself upon
+the plain. Men call it Batieia, but the gods know that it is the
+tomb of lithe Myrine. Here the Trojans and their allies divided
+their forces.
+</para>
+
+<para>
+Priam's son, great Hector of the gleaming helmet, commanded the
+Trojans, and with him were arrayed by far the greater number and
+most valiant of those who were longing for the fray.
+</para>
+
+<para>
+The Dardanians were led by brave Aeneas, whom Venus bore to
+Anchises, when she, goddess though she was, had lain with him
+upon the mountain slopes of Ida. He was not alone, for with him
+were the two sons of Antenor, Archilochus and Acamas, both
+skilled in all the arts of war.
+</para>
+
+<para>
+They that dwelt in Telea under the lowest spurs of Mt. Ida, men
+of substance, who drink the limpid waters of the Aesepus, and are
+of Trojan blood--these were led by Pandarus son of Lycaon, whom
+Apollo had taught to use the bow.
+</para>
+
+<para>
+They that held Adresteia and the land of Apaesus, with Pityeia,
+and the high mountain of Tereia--these were led by Adrestus and
+Amphius, whose breastplate was of linen. These were the sons of
+Merops of Percote, who excelled in all kinds of divination. He
+told them not to take part in the war, but they gave him no heed,
+for fate lured them to destruction.
+</para>
+
+<para>
+They that dwelt about Percote and Practius, with Sestos, Abydos,
+and Arisbe--these were led by Asius, son of Hyrtacus, a brave
+commander--Asius, the son of Hyrtacus, whom his powerful dark bay
+steeds, of the breed that comes from the river Selleis, had
+brought from Arisbe.
+</para>
+
+<para>
+Hippothous led the tribes of Pelasgian spearsmen, who dwelt in
+fertile Larissa--Hippothous, and Pylaeus of the race of Mars, two
+sons of the Pelasgian Lethus, son of Teutamus.
+</para>
+
+<para>
+Acamas and the warrior Peirous commanded the Thracians and those
+that came from beyond the mighty stream of the Hellespont.
+</para>
+
+<para>
+Euphemus, son of Troezenus, the son of Ceos, was captain of the
+Ciconian spearsmen.
+</para>
+
+<para>
+Pyraechmes led the Paeonian archers from distant Amydon, by the
+broad waters of the river Axius, the fairest that flow upon the
+earth.
+</para>
+
+<para>
+The Paphlagonians were commanded by stout-hearted Pylaemanes from
+Enetae, where the mules run wild in herds. These were they that
+held Cytorus and the country round Sesamus, with the cities by
+the river Parthenius, Cromna, Aegialus, and lofty Erithini.
+</para>
+
+<para>
+Odius and Epistrophus were captains over the Halizoni from
+distant Alybe, where there are mines of silver.
+</para>
+
+<para>
+Chromis, and Ennomus the augur, led the Mysians, but his skill in
+augury availed not to save him from destruction, for he fell by
+the hand of the fleet descendant of Aeacus in the river, where he
+slew others also of the Trojans.
+</para>
+
+<para>
+Phorcys, again, and noble Ascanius led the Phrygians from the far
+country of Ascania, and both were eager for the fray.
+</para>
+
+<para>
+Mesthles and Antiphus commanded the Meonians, sons of Talaemenes,
+born to him of the Gygaean lake. These led the Meonians, who
+dwelt under Mt. Tmolus.
+</para>
+
+<para>
+Nastes led the Carians, men of a strange speech. These held
+Miletus and the wooded mountain of Phthires, with the water of
+the river Maeander and the lofty crests of Mt. Mycale. These were
+commanded by Nastes and Amphimachus, the brave sons of Nomion. He
+came into the fight with gold about him, like a girl; fool that
+he was, his gold was of no avail to save him, for he fell in the
+river by the hand of the fleet descendant of Aeacus, and Achilles
+bore away his gold.
+</para>
+
+<para>
+Sarpedon and Glaucus led the Lycians from their distant land, by
+the eddying waters of the Xanthus.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK III</title>
+
+<para>
+When the companies were thus arrayed, each under its own captain,
+the Trojans advanced as a flight of wild fowl or cranes that
+scream overhead when rain and winter drive them over the flowing
+waters of Oceanus to bring death and destruction on the Pygmies,
+and they wrangle in the air as they fly; but the Achaeans marched
+silently, in high heart, and minded to stand by one another.
+</para>
+
+<para>
+As when the south wind spreads a curtain of mist upon the
+mountain tops, bad for shepherds but better than night for
+thieves, and a man can see no further than he can throw a stone,
+even so rose the dust from under their feet as they made all
+speed over the plain.
+</para>
+
+<para>
+When they were close up with one another, Alexandrus came forward
+as champion on the Trojan side. On his shoulders he bore the skin
+of a panther, his bow, and his sword, and he brandished two
+spears shod with bronze as a challenge to the bravest of the
+Achaeans to meet him in single fight. Menelaus saw him thus
+stride out before the ranks, and was glad as a hungry lion that
+lights on the carcase of some goat or horned stag, and devours it
+there and then, though dogs and youths set upon him. Even thus
+was Menelaus glad when his eyes caught sight of Alexandrus, for
+he deemed that now he should be revenged. He sprang, therefore,
+from his chariot, clad in his suit of armour.
+</para>
+
+<para>
+Alexandrus quailed as he saw Menelaus come forward, and shrank in
+fear of his life under cover of his men. As one who starts back
+affrighted, trembling and pale, when he comes suddenly upon a
+serpent in some mountain glade, even so did Alexandrus plunge
+into the throng of Trojan warriors, terror-stricken at the sight
+of the son of Atreus.
+</para>
+
+<para>
+Then Hector upbraided him. "Paris," said he, "evil-hearted Paris,
+fair to see, but woman-mad, and false of tongue, would that you
+had never been born, or that you had died unwed. Better so, than
+live to be disgraced and looked askance at. Will not the Achaeans
+mock at us and say that we have sent one to champion us who is
+fair to see but who has neither wit nor courage? Did you not,
+such as you are, get your following together and sail beyond the
+seas? Did you not from your a far country carry off a lovely
+woman wedded among a people of warriors--to bring sorrow upon
+your father, your city, and your whole country, but joy to your
+enemies, and hang-dog shamefacedness to yourself? And now can you
+not dare face Menelaus and learn what manner of man he is whose
+wife you have stolen? Where indeed would be your lyre and your
+love-tricks, your comely locks and your fair favour, when you
+were lying in the dust before him? The Trojans are a weak-kneed
+people, or ere this you would have had a shirt of stones for the
+wrongs you have done them."
+</para>
+
+<para>
+And Alexandrus answered, "Hector, your rebuke is just. You are
+hard as the axe which a shipwright wields at his work, and
+cleaves the timber to his liking. As the axe in his hand, so keen
+is the edge of your scorn. Still, taunt me not with the gifts
+that golden Venus has given me; they are precious; let not a man
+disdain them, for the gods give them where they are minded, and
+none can have them for the asking. If you would have me do battle
+with Menelaus, bid the Trojans and Achaeans take their seats,
+while he and I fight in their midst for Helen and all her wealth.
+Let him who shall be victorious and prove to be the better man
+take the woman and all she has, to bear them to his home, but let
+the rest swear to a solemn covenant of peace whereby you Trojans
+shall stay here in Troy, while the others go home to Argos and
+the land of the Achaeans."
+</para>
+
+<para>
+When Hector heard this he was glad, and went about among the
+Trojan ranks holding his spear by the middle to keep them back,
+and they all sat down at his bidding: but the Achaeans still
+aimed at him with stones and arrows, till Agamemnon shouted to
+them saying, "Hold, Argives, shoot not, sons of the Achaeans;
+Hector desires to speak."
+</para>
+
+<para>
+They ceased taking aim and were still, whereon Hector spoke.
+"Hear from my mouth," said he, "Trojans and Achaeans, the saying
+of Alexandrus, through whom this quarrel has come about. He bids
+the Trojans and Achaeans lay their armour upon the ground, while
+he and Menelaus fight in the midst of you for Helen and all her
+wealth. Let him who shall be victorious and prove to be the
+better man take the woman and all she has, to bear them to his
+own home, but let the rest swear to a solemn covenant of peace."
+</para>
+
+<para>
+Thus he spoke, and they all held their peace, till Menelaus of
+the loud battle-cry addressed them. "And now," he said, "hear me
+too, for it is I who am the most aggrieved. I deem that the
+parting of Achaeans and Trojans is at hand, as well it may be,
+seeing how much have suffered for my quarrel with Alexandrus and
+the wrong he did me. Let him who shall die, die, and let the
+others fight no more. Bring, then, two lambs, a white ram and a
+black ewe, for Earth and Sun, and we will bring a third for Jove.
+Moreover, you shall bid Priam come, that he may swear to the
+covenant himself; for his sons are high-handed and ill to trust,
+and the oaths of Jove must not be transgressed or taken in vain.
+Young men's minds are light as air, but when an old man comes he
+looks before and after, deeming that which shall be fairest upon
+both sides."
+</para>
+
+<para>
+The Trojans and Achaeans were glad when they heard this, for they
+thought that they should now have rest. They backed their
+chariots toward the ranks, got out of them, and put off their
+armour, laying it down upon the ground; and the hosts were near
+to one another with a little space between them. Hector sent two
+messengers to the city to bring the lambs and to bid Priam come,
+while Agamemnon told Talthybius to fetch the other lamb from the
+ships, and he did as Agamemnon had said.
+</para>
+
+<para>
+Meanwhile Iris went to Helen in the form of her sister-in-law,
+wife of the son of Antenor, for Helicaon, son of Antenor, had
+married Laodice, the fairest of Priam's daughters. She found her
+in her own room, working at a great web of purple linen, on which
+she was embroidering the battles between Trojans and Achaeans,
+that Mars had made them fight for her sake. Iris then came close
+up to her and said, "Come hither, child, and see the strange
+doings of the Trojans and Achaeans. Till now they have been
+warring upon the plain, mad with lust of battle, but now they
+have left off fighting, and are leaning upon their shields,
+sitting still with their spears planted beside them. Alexandrus
+and Menelaus are going to fight about yourself, and you are to be
+the wife of him who is the victor."
+</para>
+
+<para>
+Thus spoke the goddess, and Helen's heart yearned after her
+former husband, her city, and her parents. She threw a white
+mantle over her head, and hurried from her room, weeping as she
+went, not alone, but attended by two of her handmaids, Aethrae,
+daughter of Pittheus, and Clymene. And straightway they were at
+the Scaean gates.
+</para>
+
+<para>
+The two sages, Ucalegon and Antenor, elders of the people, were
+seated by the Scaean gates, with Priam, Panthous, Thymoetes,
+Lampus, Clytius, and Hiketaon of the race of Mars. These were too
+old to fight, but they were fluent orators, and sat on the tower
+like cicales that chirrup delicately from the boughs of some high
+tree in a wood. When they saw Helen coming towards the tower,
+they said softly to one another, "Small wonder that Trojans and
+Achaeans should endure so much and so long, for the sake of a
+woman so marvellously and divinely lovely. Still, fair though she
+be, let them take her and go, or she will breed sorrow for us and
+for our children after us."
+</para>
+
+<para>
+But Priam bade her draw nigh. "My child," said he, "take your
+seat in front of me that you may see your former husband, your
+kinsmen and your friends. I lay no blame upon you, it is the
+gods, not you who are to blame. It is they that have brought
+about this terrible war with the Achaeans. Tell me, then, who is
+yonder huge hero so great and goodly? I have seen men taller by a
+head, but none so comely and so royal. Surely he must be a king."
+</para>
+
+<para>
+"Sir," answered Helen, "father of my husband, dear and reverend
+in my eyes, would that I had chosen death rather than to have
+come here with your son, far from my bridal chamber, my friends,
+my darling daughter, and all the companions of my girlhood. But
+it was not to be, and my lot is one of tears and sorrow. As for
+your question, the hero of whom you ask is Agamemnon, son of
+Atreus, a good king and a brave soldier, brother-in-law as surely
+as that he lives, to my abhorred and miserable self."
+</para>
+
+<para>
+The old man marvelled at him and said, "Happy son of Atreus,
+child of good fortune. I see that the Achaeans are subject to you
+in great multitudes. When I was in Phrygia I saw much horsemen,
+the people of Otreus and of Mygdon, who were camping upon the
+banks of the river Sangarius; I was their ally, and with them
+when the Amazons, peers of men, came up against them, but even
+they were not so many as the Achaeans."
+</para>
+
+<para>
+The old man next looked upon Ulysses; "Tell me," he said, "who is
+that other, shorter by a head than Agamemnon, but broader across
+the chest and shoulders? His armour is laid upon the ground, and
+he stalks in front of the ranks as it were some great woolly ram
+ordering his ewes."
+</para>
+
+<para>
+And Helen answered, "He is Ulysses, a man of great craft, son of
+Laertes. He was born in rugged Ithaca, and excels in all manner
+of stratagems and subtle cunning."
+</para>
+
+<para>
+On this Antenor said, "Madam, you have spoken truly. Ulysses once
+came here as envoy about yourself, and Menelaus with him. I
+received them in my own house, and therefore know both of them by
+sight and conversation. When they stood up in presence of the
+assembled Trojans, Menelaus was the broader shouldered, but when
+both were seated Ulysses had the more royal presence. After a
+time they delivered their message, and the speech of Menelaus ran
+trippingly on the tongue; he did not say much, for he was a man
+of few words, but he spoke very clearly and to the point, though
+he was the younger man of the two; Ulysses, on the other hand,
+when he rose to speak, was at first silent and kept his eyes
+fixed upon the ground. There was no play nor graceful movement of
+his sceptre; he kept it straight and stiff like a man unpractised
+in oratory--one might have taken him for a mere churl or
+simpleton; but when he raised his voice, and the words came
+driving from his deep chest like winter snow before the wind,
+then there was none to touch him, and no man thought further of
+what he looked like."
+</para>
+
+<para>
+Priam then caught sight of Ajax and asked, "Who is that great and
+goodly warrior whose head and broad shoulders tower above the
+rest of the Argives?"
+</para>
+
+<para>
+"That," answered Helen, "is huge Ajax, bulwark of the Achaeans,
+and on the other side of him, among the Cretans, stands Idomeneus
+looking like a god, and with the captains of the Cretans round
+him. Often did Menelaus receive him as a guest in our house when
+he came visiting us from Crete. I see, moreover, many other
+Achaeans whose names I could tell you, but there are two whom I
+can nowhere find, Castor, breaker of horses, and Pollux the
+mighty boxer; they are children of my mother, and own brothers to
+myself. Either they have not left Lacedaemon, or else, though
+they have brought their ships, they will not show themselves in
+battle for the shame and disgrace that I have brought upon them."
+</para>
+
+<para>
+She knew not that both these heroes were already lying under the
+earth in their own land of Lacedaemon.
+</para>
+
+<para>
+Meanwhile the heralds were bringing the holy oath-offerings
+through the city--two lambs and a goatskin of wine, the gift of
+earth; and Idaeus brought the mixing bowl and the cups of gold.
+He went up to Priam and said, "Son of Laomedon, the princes of
+the Trojans and Achaeans bid you come down on to the plain and
+swear to a solemn covenant. Alexandrus and Menelaus are to fight
+for Helen in single combat, that she and all her wealth may go
+with him who is the victor. We are to swear to a solemn covenant
+of peace whereby we others shall dwell here in Troy, while the
+Achaeans return to Argos and the land of the Achaeans."
+</para>
+
+<para>
+The old man trembled as he heard, but bade his followers yoke the
+horses, and they made all haste to do so. He mounted the chariot,
+gathered the reins in his hand, and Antenor took his seat beside
+him; they then drove through the Scaean gates on to the plain.
+When they reached the ranks of the Trojans and Achaeans they left
+the chariot, and with measured pace advanced into the space
+between the hosts.
+</para>
+
+<para>
+Agamemnon and Ulysses both rose to meet them. The attendants
+brought on the oath-offerings and mixed the wine in the
+mixing-bowls; they poured water over the hands of the chieftains,
+and the son of Atreus drew the dagger that hung by his sword, and
+cut wool from the lambs' heads; this the men-servants gave about
+among the Trojan and Achaean princes, and the son of Atreus
+lifted up his hands in prayer. "Father Jove," he cried, "that
+rulest in Ida, most glorious in power, and thou oh Sun, that
+seest and givest ear to all things, Earth and Rivers, and ye who
+in the realms below chastise the soul of him that has broken his
+oath, witness these rites and guard them, that they be not vain.
+If Alexandrus kills Menelaus, let him keep Helen and all her
+wealth, while we sail home with our ships; but if Menelaus kills
+Alexandrus, let the Trojans give back Helen and all that she has;
+let them moreover pay such fine to the Achaeans as shall be
+agreed upon, in testimony among those that shall be born
+hereafter. And if Priam and his sons refuse such fine when
+Alexandrus has fallen, then will I stay here and fight on till I
+have got satisfaction."
+</para>
+
+<para>
+As he spoke he drew his knife across the throats of the victims,
+and laid them down gasping and dying upon the ground, for the
+knife had reft them of their strength. Then they poured wine from
+the mixing-bowl into the cups, and prayed to the everlasting
+gods, saying, Trojans and Achaeans among one another, "Jove, most
+great and glorious, and ye other everlasting gods, grant that the
+brains of them who shall first sin against their oaths--of them
+and their children--may be shed upon the ground even as this
+wine, and let their wives become the slaves of strangers."
+</para>
+
+<para>
+Thus they prayed, but not as yet would Jove grant them their
+prayer. Then Priam, descendant of Dardanus, spoke, saying, "Hear
+me, Trojans and Achaeans, I will now go back to the wind-beaten
+city of Ilius: I dare not with my own eyes witness this fight
+between my son and Menelaus, for Jove and the other immortals
+alone know which shall fall."
+</para>
+
+<para>
+On this he laid the two lambs on his chariot and took his seat.
+He gathered the reins in his hand, and Antenor sat beside him;
+the two then went back to Ilius. Hector and Ulysses measured the
+ground, and cast lots from a helmet of bronze to see which should
+take aim first. Meanwhile the two hosts lifted up their hands and
+prayed saying, "Father Jove, that rulest from Ida, most glorious
+in power, grant that he who first brought about this war between
+us may die, and enter the house of Hades, while we others remain
+at peace and abide by our oaths."
+</para>
+
+<para>
+Great Hector now turned his head aside while he shook the helmet,
+and the lot of Paris flew out first. The others took their
+several stations, each by his horses and the place where his arms
+were lying, while Alexandrus, husband of lovely Helen, put on his
+goodly armour. First he greaved his legs with greaves of good
+make and fitted with ancle-clasps of silver; after this he donned
+the cuirass of his brother Lycaon, and fitted it to his own body;
+he hung his silver-studded sword of bronze about his shoulders,
+and then his mighty shield. On his comely head he set his helmet,
+well-wrought, with a crest of horse-hair that nodded menacingly
+above it, and he grasped a redoubtable spear that suited his
+hands. In like fashion Menelaus also put on his armour.
+</para>
+
+<para>
+When they had thus armed, each amid his own people, they strode
+fierce of aspect into the open space, and both Trojans and
+Achaeans were struck with awe as they beheld them. They stood
+near one another on the measured ground, brandishing their
+spears, and each furious against the other. Alexandrus aimed
+first, and struck the round shield of the son of Atreus, but the
+spear did not pierce it, for the shield turned its point.
+Menelaus next took aim, praying to Father Jove as he did so.
+"King Jove," he said, "grant me revenge on Alexandrus who has
+wronged me; subdue him under my hand that in ages yet to come a
+man may shrink from doing ill deeds in the house of his host."
+</para>
+
+<para>
+He poised his spear as he spoke, and hurled it at the shield of
+Alexandrus. Through shield and cuirass it went, and tore the
+shirt by his flank, but Alexandrus swerved aside, and thus saved
+his life. Then the son of Atreus drew his sword, and drove at the
+projecting part of his helmet, but the sword fell shivered in
+three or four pieces from his hand, and he cried, looking towards
+Heaven, "Father Jove, of all gods thou art the most despiteful; I
+made sure of my revenge, but the sword has broken in my hand, my
+spear has been hurled in vain, and I have not killed him."
+</para>
+
+<para>
+With this he flew at Alexandrus, caught him by the horsehair
+plume of his helmet, and began dragging him towards the Achaeans.
+The strap of the helmet that went under his chin was choking him,
+and Menelaus would have dragged him off to his own great glory
+had not Jove's daughter Venus been quick to mark and to break the
+strap of oxhide, so that the empty helmet came away in his hand.
+This he flung to his comrades among the Achaeans, and was again
+springing upon Alexandrus to run him through with a spear, but
+Venus snatched him up in a moment (as a god can do), hid him
+under a cloud of darkness, and conveyed him to his own
+bedchamber.
+</para>
+
+<para>
+Then she went to call Helen, and found her on a high tower with
+the Trojan women crowding round her. She took the form of an old
+woman who used to dress wool for her when she was still in
+Lacedaemon, and of whom she was very fond. Thus disguised she
+plucked her by perfumed robe and said, "Come hither; Alexandrus
+says you are to go to the house; he is on his bed in his own
+room, radiant with beauty and dressed in gorgeous apparel. No one
+would think he had just come from fighting, but rather that he
+was going to a dance, or had done dancing and was sitting down."
+</para>
+
+<para>
+With these words she moved the heart of Helen to anger. When she
+marked the beautiful neck of the goddess, her lovely bosom, and
+sparkling eyes, she marvelled at her and said, "Goddess, why do
+you thus beguile me? Are you going to send me afield still
+further to some man whom you have taken up in Phrygia or fair
+Meonia? Menelaus has just vanquished Alexandrus, and is to take
+my hateful self back with him. You are come here to betray me. Go
+sit with Alexandrus yourself; henceforth be goddess no longer;
+never let your feet carry you back to Olympus; worry about him
+and look after him till he make you his wife, or, for the matter
+of that, his slave--but me? I shall not go; I can garnish his bed
+no longer; I should be a by-word among all the women of Troy.
+Besides, I have trouble on my mind."
+</para>
+
+<para>
+Venus was very angry, and said, "Bold hussy, do not provoke me;
+if you do, I shall leave you to your fate and hate you as much as
+I have loved you. I will stir up fierce hatred between Trojans
+and Achaeans, and you shall come to a bad end."
+</para>
+
+<para>
+At this Helen was frightened. She wrapped her mantle about her
+and went in silence, following the goddess and unnoticed by the
+Trojan women.
+</para>
+
+<para>
+When they came to the house of Alexandrus the maid-servants set
+about their work, but Helen went into her own room, and the
+laughter-loving goddess took a seat and set it for her facing
+Alexandrus. On this Helen, daughter of aegis-bearing Jove, sat
+down, and with eyes askance began to upbraid her husband.
+</para>
+
+<para>
+"So you are come from the fight," said she; "would that you had
+fallen rather by the hand of that brave man who was my husband.
+You used to brag that you were a better man with hands and spear
+than Menelaus. Go, then, and challenge him again--but I should
+advise you not to do so, for if you are foolish enough to meet
+him in single combat, you will soon fall by his spear."
+</para>
+
+<para>
+And Paris answered, "Wife, do not vex me with your reproaches.
+This time, with the help of Minerva, Menelaus has vanquished me;
+another time I may myself be victor, for I too have gods that
+will stand by me. Come, let us lie down together and make
+friends. Never yet was I so passionately enamoured of you as at
+this moment--not even when I first carried you off from
+Lacedaemon and sailed away with you--not even when I had converse
+with you upon the couch of love in the island of Cranae was I so
+enthralled by desire of you as now." On this he led her towards
+the bed, and his wife went with him.
+</para>
+
+<para>
+Thus they laid themselves on the bed together; but the son of
+Atreus strode among the throng, looking everywhere for
+Alexandrus, and no man, neither of the Trojans nor of the allies,
+could find him. If they had seen him they were in no mind to hide
+him, for they all of them hated him as they did death itself.
+Then Agamemnon, king of men, spoke, saying, "Hear me, Trojans,
+Dardanians, and allies. The victory has been with Menelaus;
+therefore give back Helen with all her wealth, and pay such fine
+as shall be agreed upon, in testimony among them that shall be
+born hereafter."
+</para>
+
+<para>
+Thus spoke the son of Atreus, and the Achaeans shouted in
+applause.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK IV</title>
+
+<para>
+Now the gods were sitting with Jove in council upon the golden
+floor while Hebe went round pouring out nectar for them to drink,
+and as they pledged one another in their cups of gold they looked
+down upon the town of Troy. The son of Saturn then began to tease
+Juno, talking at her so as to provoke her. "Menelaus," said he,
+"has two good friends among the goddesses, Juno of Argos, and
+Minerva of Alalcomene, but they only sit still and look on, while
+Venus keeps ever by Alexandrus' side to defend him in any danger;
+indeed she has just rescued him when he made sure that it was all
+over with him--for the victory really did lie with Menelaus. We
+must consider what we shall do about all this; shall we set them
+fighting anew or make peace between them? If you will agree to
+this last Menelaus can take back Helen and the city of Priam may
+remain still inhabited."
+</para>
+
+<para>
+Minerva and Juno muttered their discontent as they sat side by
+side hatching mischief for the Trojans. Minerva scowled at her
+father, for she was in a furious passion with him, and said
+nothing, but Juno could not contain herself. "Dread son of
+Saturn," said she, "what, pray, is the meaning of all this? Is my
+trouble, then, to go for nothing, and the sweat that I have
+sweated, to say nothing of my horses, while getting the people
+together against Priam and his children? Do as you will, but we
+other gods shall not all of us approve your counsel."
+</para>
+
+<para>
+Jove was angry and answered, "My dear, what harm have Priam and
+his sons done you that you are so hotly bent on sacking the city
+of Ilius? Will nothing do for you but you must within their walls
+and eat Priam raw, with his sons and all the other Trojans to
+boot? Have it your own way then; for I would not have this matter
+become a bone of contention between us. I say further, and lay my
+saying to your heart, if ever I want to sack a city belonging to
+friends of yours, you must not try to stop me; you will have to
+let me do it, for I am giving in to you sorely against my will.
+Of all inhabited cities under the sun and stars of heaven, there
+was none that I so much respected as Ilius with Priam and his
+whole people. Equitable feasts were never wanting about my altar,
+nor the savour of burning fat, which is honour due to ourselves."
+</para>
+
+<para>
+"My own three favourite cities," answered Juno, "are Argos,
+Sparta, and Mycenae. Sack them whenever you may be displeased
+with them. I shall not defend them and I shall not care. Even if
+I did, and tried to stay you, I should take nothing by it, for
+you are much stronger than I am, but I will not have my own work
+wasted. I too am a god and of the same race with yourself. I am
+Saturn's eldest daughter, and am honourable not on this ground
+only, but also because I am your wife, and you are king over the
+gods. Let it be a case, then, of give-and-take between us, and
+the rest of the gods will follow our lead. Tell Minerva to go and
+take part in the fight at once, and let her contrive that the
+Trojans shall be the first to break their oaths and set upon the
+Achaeans."
+</para>
+
+<para>
+The sire of gods and men heeded her words, and said to Minerva,
+"Go at once into the Trojan and Achaean hosts, and contrive that
+the Trojans shall be the first to break their oaths and set upon
+the Achaeans."
+</para>
+
+<para>
+This was what Minerva was already eager to do, so down she darted
+from the topmost summits of Olympus. She shot through the sky as
+some brilliant meteor which the son of scheming Saturn has sent
+as a sign to mariners or to some great army, and a fiery train of
+light follows in its wake. The Trojans and Achaeans were struck
+with awe as they beheld, and one would turn to his neighbour,
+saying, "Either we shall again have war and din of combat, or
+Jove the lord of battle will now make peace between us."
+</para>
+
+<para>
+Thus did they converse. Then Minerva took the form of Laodocus,
+son of Antenor, and went through the ranks of the Trojans to find
+Pandarus, the redoubtable son of Lycaon. She found him standing
+among the stalwart heroes who had followed him from the banks of
+the Aesopus, so she went close up to him and said, "Brave son of
+Lycaon, will you do as I tell you? If you dare send an arrow at
+Menelaus you will win honour and thanks from all the Trojans, and
+especially from prince Alexandrus--he would be the first to
+requite you very handsomely if he could see Menelaus mount his
+funeral pyre, slain by an arrow from your hand. Take your home
+aim then, and pray to Lycian Apollo, the famous archer; vow that
+when you get home to your strong city of Zelea you will offer a
+hecatomb of firstling lambs in his honour."
+</para>
+
+<para>
+His fool's heart was persuaded, and he took his bow from its
+case. This bow was made from the horns of a wild ibex which he
+had killed as it was bounding from a rock; he had stalked it, and
+it had fallen as the arrow struck it to the heart. Its horns were
+sixteen palms long, and a worker in horn had made them into a
+bow, smoothing them well down, and giving them tips of gold. When
+Pandarus had strung his bow he laid it carefully on the ground,
+and his brave followers held their shields before him lest the
+Achaeans should set upon him before he had shot Menelaus. Then he
+opened the lid of his quiver and took out a winged arrow that had
+not yet been shot, fraught with the pangs of death. He laid the
+arrow on the string and prayed to Lycian Apollo, the famous
+archer, vowing that when he got home to his strong city of Zelea
+he would offer a hecatomb of firstling lambs in his honour. He
+laid the notch of the arrow on the oxhide bowstring, and drew
+both notch and string to his breast till the arrow-head was near
+the bow; then when the bow was arched into a half-circle he let
+fly, and the bow twanged, and the string sang as the arrow flew
+gladly on over the heads of the throng.
+</para>
+
+<para>
+But the blessed gods did not forget thee, O Menelaus, and Jove's
+daughter, driver of the spoil, was the first to stand before thee
+and ward off the piercing arrow. She turned it from his skin as a
+mother whisks a fly from off her child when it is sleeping
+sweetly; she guided it to the part where the golden buckles of
+the belt that passed over his double cuirass were fastened, so
+the arrow struck the belt that went tightly round him. It went
+right through this and through the cuirass of cunning
+workmanship; it also pierced the belt beneath it, which he wore
+next his skin to keep out darts or arrows; it was this that
+served him in the best stead, nevertheless the arrow went through
+it and grazed the top of the skin, so that blood began flowing
+from the wound.
+</para>
+
+<para>
+As when some woman of Meonia or Caria strains purple dye on to a
+piece of ivory that is to be the cheek-piece of a horse, and is
+to be laid up in a treasure house--many a knight is fain to bear
+it, but the king keeps it as an ornament of which both horse and
+driver may be proud--even so, O Menelaus, were your shapely
+thighs and your legs down to your fair ancles stained with blood.
+</para>
+
+<para>
+When King Agamemnon saw the blood flowing from the wound he was
+afraid, and so was brave Menelaus himself till he saw that the
+barbs of the arrow and the thread that bound the arrow-head to
+the shaft were still outside the wound. Then he took heart, but
+Agamemnon heaved a deep sigh as he held Menelaus's hand in his
+own, and his comrades made moan in concert. "Dear brother," he
+cried, "I have been the death of you in pledging this covenant
+and letting you come forward as our champion. The Trojans have
+trampled on their oaths and have wounded you; nevertheless the
+oath, the blood of lambs, the drink-offerings and the right hands
+of fellowship in which we have put our trust shall not be vain.
+If he that rules Olympus fulfil it not here and now, he will yet
+fulfil it hereafter, and they shall pay dearly with their lives
+and with their wives and children. The day will surely come when
+mighty Ilius shall be laid low, with Priam and Priam's people,
+when the son of Saturn from his high throne shall overshadow them
+with his awful aegis in punishment of their present treachery.
+This shall surely be; but how, Menelaus, shall I mourn you, if it
+be your lot now to die? I should return to Argos as a by-word,
+for the Achaeans will at once go home. We shall leave Priam and
+the Trojans the glory of still keeping Helen, and the earth will
+rot your bones as you lie here at Troy with your purpose not
+fulfilled. Then shall some braggart Trojan leap upon your tomb
+and say, 'Ever thus may Agamemnon wreak his vengeance; he brought
+his army in vain; he is gone home to his own land with empty
+ships, and has left Menelaus behind him.' Thus will one of them
+say, and may the earth then swallow me."
+</para>
+
+<para>
+But Menelaus reassured him and said, "Take heart, and do not
+alarm the people; the arrow has not struck me in a mortal part,
+for my outer belt of burnished metal first stayed it, and under
+this my cuirass and the belt of mail which the bronze-smiths made
+me."
+</para>
+
+<para>
+And Agamemnon answered, "I trust, dear Menelaus, that it may be
+even so, but the surgeon shall examine your wound and lay herbs
+upon it to relieve your pain."
+</para>
+
+<para>
+He then said to Talthybius, "Talthybius, tell Machaon, son to the
+great physician, Aesculapius, to come and see Menelaus
+immediately. Some Trojan or Lycian archer has wounded him with an
+arrow to our dismay, and to his own great glory."
+</para>
+
+<para>
+Talthybius did as he was told, and went about the host trying to
+find Machaon. Presently he found standing amid the brave warriors
+who had followed him from Tricca; thereon he went up to him and
+said, "Son of Aesculapius, King Agamemnon says you are to come
+and see Menelaus immediately. Some Trojan or Lycian archer has
+wounded him with an arrow to our dismay and to his own great
+glory."
+</para>
+
+<para>
+Thus did he speak, and Machaon was moved to go. They passed
+through the spreading host of the Achaeans and went on till they
+came to the place where Menelaus had been wounded and was lying
+with the chieftains gathered in a circle round him. Machaon
+passed into the middle of the ring and at once drew the arrow
+from the belt, bending its barbs back through the force with
+which he pulled it out. He undid the burnished belt, and beneath
+this the cuirass and the belt of mail which the bronze-smiths had
+made; then, when he had seen the wound, he wiped away the blood
+and applied some soothing drugs which Chiron had given to
+Aesculapius out of the good will he bore him.
+</para>
+
+<para>
+While they were thus busy about Menelaus, the Trojans came
+forward against them, for they had put on their armour, and now
+renewed the fight.
+</para>
+
+<para>
+You would not have then found Agamemnon asleep nor cowardly and
+unwilling to fight, but eager rather for the fray. He left his
+chariot rich with bronze and his panting steeds in charge of
+Eurymedon, son of Ptolemaeus the son of Peiraeus, and bade him
+hold them in readiness against the time his limbs should weary of
+going about and giving orders to so many, for he went among the
+ranks on foot. When he saw men hasting to the front he stood by
+them and cheered them on. "Argives," said he, "slacken not one
+whit in your onset; father Jove will be no helper of liars; the
+Trojans have been the first to break their oaths and to attack
+us; therefore they shall be devoured of vultures; we shall take
+their city and carry off their wives and children in our ships."
+</para>
+
+<para>
+But he angrily rebuked those whom he saw shirking and disinclined
+to fight. "Argives," he cried, "cowardly miserable creatures,
+have you no shame to stand here like frightened fawns who, when
+they can no longer scud over the plain, huddle together, but show
+no fight? You are as dazed and spiritless as deer. Would you wait
+till the Trojans reach the sterns of our ships as they lie on the
+shore, to see whether the son of Saturn will hold his hand over
+you to protect you?"
+</para>
+
+<para>
+Thus did he go about giving his orders among the ranks. Passing
+through the crowd, he came presently on the Cretans, arming round
+Idomeneus, who was at their head, fierce as a wild boar, while
+Meriones was bringing up the battalions that were in the rear.
+Agamemnon was glad when he saw him, and spoke him fairly.
+"Idomeneus," said he, "I treat you with greater distinction than
+I do any others of the Achaeans, whether in war or in other
+things, or at table. When the princes are mixing my choicest
+wines in the mixing-bowls, they have each of them a fixed
+allowance, but your cup is kept always full like my own, that you
+may drink whenever you are minded. Go, therefore, into battle,
+and show yourself the man you have been always proud to be."
+</para>
+
+<para>
+Idomeneus answered, "I will be a trusty comrade, as I promised
+you from the first I would be. Urge on the other Achaeans, that
+we may join battle at once, for the Trojans have trampled upon
+their covenants. Death and destruction shall be theirs, seeing
+they have been the first to break their oaths and to attack us."
+</para>
+
+<para>
+The son of Atreus went on, glad at heart, till he came upon the
+two Ajaxes arming themselves amid a host of foot-soldiers. As
+when a goat-herd from some high post watches a storm drive over
+the deep before the west wind--black as pitch is the offing and a
+mighty whirlwind draws towards him, so that he is afraid and
+drives his flock into a cave--even thus did the ranks of stalwart
+youths move in a dark mass to battle under the Ajaxes, horrid
+with shield and spear. Glad was King Agamemnon when he saw them.
+"No need," he cried, "to give orders to such leaders of the
+Argives as you are, for of your own selves you spur your men on
+to fight with might and main. Would, by father Jove, Minerva, and
+Apollo that all were so minded as you are, for the city of Priam
+would then soon fall beneath our hands, and we should sack it."
+</para>
+
+<para>
+With this he left them and went onward to Nestor, the facile
+speaker of the Pylians, who was marshalling his men and urging
+them on, in company with Pelagon, Alastor, Chromius, Haemon, and
+Bias shepherd of his people. He placed his knights with their
+chariots and horses in the front rank, while the foot-soldiers,
+brave men and many, whom he could trust, were in the rear. The
+cowards he drove into the middle, that they might fight whether
+they would or no. He gave his orders to the knights first,
+bidding them hold their horses well in hand, so as to avoid
+confusion. "Let no man," he said, "relying on his strength or
+horsemanship, get before the others and engage singly with the
+Trojans, nor yet let him lag behind or you will weaken your
+attack; but let each when he meets an enemy's chariot throw his
+spear from his own; this be much the best; this is how the men of
+old took towns and strongholds; in this wise were they minded."
+</para>
+
+<para>
+Thus did the old man charge them, for he had been in many a
+fight, and King Agamemnon was glad. "I wish," he said to him,
+"that your limbs were as supple and your strength as sure as your
+judgment is; but age, the common enemy of mankind, has laid his
+hand upon you; would that it had fallen upon some other, and that
+you were still young."
+</para>
+
+<para>
+And Nestor, knight of Gerene, answered, "Son of Atreus, I too
+would gladly be the man I was when I slew mighty Ereuthalion; but
+the gods will not give us everything at one and the same time. I
+was then young, and now I am old; still I can go with my knights
+and give them that counsel which old men have a right to give.
+The wielding of the spear I leave to those who are younger and
+stronger than myself."
+</para>
+
+<para>
+Agamemnon went his way rejoicing, and presently found Menestheus,
+son of Peteos, tarrying in his place, and with him were the
+Athenians loud of tongue in battle. Near him also tarried cunning
+Ulysses, with his sturdy Cephallenians round him; they had not
+yet heard the battle-cry, for the ranks of Trojans and Achaeans
+had only just begun to move, so they were standing still, waiting
+for some other columns of the Achaeans to attack the Trojans and
+begin the fighting. When he saw this Agamemnon rebuked them and
+said, "Son of Peteos, and you other, steeped in cunning, heart of
+guile, why stand you here cowering and waiting on others? You two
+should be of all men foremost when there is hard fighting to be
+done, for you are ever foremost to accept my invitation when we
+councillors of the Achaeans are holding feast. You are glad
+enough then to take your fill of roast meats and to drink wine as
+long as you please, whereas now you would not care though you saw
+ten columns of Achaeans engage the enemy in front of you."
+</para>
+
+<para>
+Ulysses glared at him and answered, "Son of Atreus, what are you
+talking about? How can you say that we are slack? When the
+Achaeans are in full fight with the Trojans, you shall see, if
+you care to do so, that the father of Telemachus will join battle
+with the foremost of them. You are talking idly."
+</para>
+
+<para>
+When Agamemnon saw that Ulysses was angry, he smiled pleasantly
+at him and withdrew his words. "Ulysses," said he, "noble son of
+Laertes, excellent in all good counsel, I have neither fault to
+find nor orders to give you, for I know your heart is right, and
+that you and I are of a mind. Enough; I will make you amends for
+what I have said, and if any ill has now been spoken may the gods
+bring it to nothing."
+</para>
+
+<para>
+He then left them and went on to others. Presently he saw the son
+of Tydeus, noble Diomed, standing by his chariot and horses, with
+Sthenelus the son of Capaneus beside him; whereon he began to
+upbraid him. "Son of Tydeus," he said, "why stand you cowering
+here upon the brink of battle? Tydeus did not shrink thus, but
+was ever ahead of his men when leading them on against the foe--
+so, at least, say they that saw him in battle, for I never set
+eyes upon him myself. They say that there was no man like him. He
+came once to Mycenae, not as an enemy but as a guest, in company
+with Polynices to recruit his forces, for they were levying war
+against the strong city of Thebes, and prayed our people for a
+body of picked men to help them. The men of Mycenae were willing
+to let them have one, but Jove dissuaded them by showing them
+unfavourable omens. Tydeus, therefore, and Polynices went their
+way. When they had got as far the deep-meadowed and rush-grown
+banks of the Aesopus, the Achaeans sent Tydeus as their envoy,
+and he found the Cadmeans gathered in great numbers to a banquet
+in the house of Eteocles. Stranger though he was, he knew no fear
+on finding himself single-handed among so many, but challenged
+them to contests of all kinds, and in each one of them was at
+once victorious, so mightily did Minerva help him. The Cadmeans
+were incensed at his success, and set a force of fifty youths
+with two captains--the godlike hero Maeon, son of Haemon, and
+Polyphontes, son of Autophonus--at their head, to lie in wait for
+him on his return journey; but Tydeus slew every man of them,
+save only Maeon, whom he let go in obedience to heaven's omens.
+Such was Tydeus of Aetolia. His son can talk more glibly, but he
+cannot fight as his father did."
+</para>
+
+<para>
+Diomed made no answer, for he was shamed by the rebuke of
+Agamemnon; but the son of Capaneus took up his words and said,
+"Son of Atreus, tell no lies, for you can speak truth if you
+will. We boast ourselves as even better men than our fathers; we
+took seven-gated Thebes, though the wall was stronger and our men
+were fewer in number, for we trusted in the omens of the gods and
+in the help of Jove, whereas they perished through their own
+sheer folly; hold not, then, our fathers in like honour with us."
+</para>
+
+<para>
+Diomed looked sternly at him and said, "Hold your peace, my
+friend, as I bid you. It is not amiss that Agamemnon should urge
+the Achaeans forward, for the glory will be his if we take the
+city, and his the shame if we are vanquished. Therefore let us
+acquit ourselves with valour."
+</para>
+
+<para>
+As he spoke he sprang from his chariot, and his armour rang so
+fiercely about his body that even a brave man might well have
+been scared to hear it.
+</para>
+
+<para>
+As when some mighty wave that thunders on the beach when the west
+wind has lashed it into fury--it has reared its head afar and now
+comes crashing down on the shore; it bows its arching crest high
+over the jagged rocks and spews its salt foam in all
+directions--even so did the serried phalanxes of the Danaans
+march steadfastly to battle. The chiefs gave orders each to his
+own people, but the men said never a word; no man would think it,
+for huge as the host was, it seemed as though there was not a
+tongue among them, so silent were they in their obedience; and as
+they marched the armour about their bodies glistened in the sun.
+But the clamour of the Trojan ranks was as that of many thousand
+ewes that stand waiting to be milked in the yards of some rich
+flockmaster, and bleat incessantly in answer to the bleating of
+their lambs; for they had not one speech nor language, but their
+tongues were diverse, and they came from many different places.
+These were inspired of Mars, but the others by Minerva--and with
+them came Panic, Rout, and Strife whose fury never tires, sister
+and friend of murderous Mars, who, from being at first but low in
+stature, grows till she uprears her head to heaven, though her
+feet are still on earth. She it was that went about among them
+and flung down discord to the waxing of sorrow with even hand
+between them.
+</para>
+
+<para>
+When they were got together in one place shield clashed with
+shield and spear with spear in the rage of battle. The bossed
+shields beat one upon another, and there was a tramp as of a
+great multitude--death-cry and shout of triumph of slain and
+slayers, and the earth ran red with blood. As torrents swollen
+with rain course madly down their deep channels till the angry
+floods meet in some gorge, and the shepherd on the hillside hears
+their roaring from afar--even such was the toil and uproar of the
+hosts as they joined in battle.
+</para>
+
+<para>
+First Antilochus slew an armed warrior of the Trojans, Echepolus,
+son of Thalysius, fighting in the foremost ranks. He struck at
+the projecting part of his helmet and drove the spear into his
+brow; the point of bronze pierced the bone, and darkness veiled
+his eyes; headlong as a tower he fell amid the press of the
+fight, and as he dropped King Elephenor, son of Chalcodon and
+captain of the proud Abantes began dragging him out of reach of
+the darts that were falling around him, in haste to strip him of
+his armour. But his purpose was not for long; Agenor saw him
+haling the body away, and smote him in the side with his
+bronze-shod spear--for as he stooped his side was left
+unprotected by his shield--and thus he perished. Then the fight
+between Trojans and Achaeans grew furious over his body, and they
+flew upon each other like wolves, man and man crushing one upon
+the other.
+</para>
+
+<para>
+Forthwith Ajax, son of Telamon, slew the fair youth Simoeisius,
+son of Anthemion, whom his mother bore by the banks of the
+Simois, as she was coming down from Mt. Ida, where she had been
+with her parents to see their flocks. Therefore he was named
+Simoeisius, but he did not live to pay his parents for his
+rearing, for he was cut off untimely by the spear of mighty Ajax,
+who struck him in the breast by the right nipple as he was coming
+on among the foremost fighters; the spear went right through his
+shoulder, and he fell as a poplar that has grown straight and
+tall in a meadow by some mere, and its top is thick with
+branches. Then the wheelwright lays his axe to its roots that he
+may fashion a felloe for the wheel of some goodly chariot, and it
+lies seasoning by the waterside. In such wise did Ajax fell to
+earth Simoeisius, son of Anthemion. Thereon Antiphus of the
+gleaming corslet, son of Priam, hurled a spear at Ajax from amid
+the crowd and missed him, but he hit Leucus, the brave comrade of
+Ulysses, in the groin, as he was dragging the body of Simoeisius
+over to the other side; so he fell upon the body and loosed his
+hold upon it. Ulysses was furious when he saw Leucus slain, and
+strode in full armour through the front ranks till he was quite
+close; then he glared round about him and took aim, and the
+Trojans fell back as he did so. His dart was not sped in vain,
+for it struck Democoon, the bastard son of Priam, who had come to
+him from Abydos, where he had charge of his father's mares.
+Ulysses, infuriated by the death of his comrade, hit him with his
+spear on one temple, and the bronze point came through on the
+other side of his forehead. Thereon darkness veiled his eyes, and
+his armour rang rattling round him as he fell heavily to the
+ground. Hector, and they that were in front, then gave round
+while the Argives raised a shout and drew off the dead, pressing
+further forward as they did so. But Apollo looked down from
+Pergamus and called aloud to the Trojans, for he was displeased.
+"Trojans," he cried, "rush on the foe, and do not let yourselves
+be thus beaten by the Argives. Their skins are not stone nor iron
+that when hit them you do them no harm. Moreover, Achilles, the
+son of lovely Thetis, is not fighting, but is nursing his anger
+at the ships."
+</para>
+
+<para>
+Thus spoke the mighty god, crying to them from the city, while
+Jove's redoubtable daughter, the Trito-born, went about among the
+host of the Achaeans, and urged them forward whenever she beheld
+them slackening.
+</para>
+
+<para>
+Then fate fell upon Diores, son of Amarynceus, for he was struck
+by a jagged stone near the ancle of his right leg. He that hurled
+it was Peirous, son of Imbrasus, captain of the Thracians, who
+had come from Aenus; the bones and both the tendons were crushed
+by the pitiless stone. He fell to the ground on his back, and in
+his death throes stretched out his hands towards his comrades.
+But Peirous, who had wounded him, sprang on him and thrust a
+spear into his belly, so that his bowels came gushing out upon
+the ground, and darkness veiled his eyes. As he was leaving the
+body, Thoas of Aetolia struck him in the chest near the nipple,
+and the point fixed itself in his lungs. Thoas came close up to
+him, pulled the spear out of his chest, and then drawing his
+sword, smote him in the middle of the belly so that he died; but
+he did not strip him of his armour, for his Thracian comrades,
+men who wear their hair in a tuft at the top of their heads,
+stood round the body and kept him off with their long spears for
+all his great stature and valour; so he was driven back. Thus the
+two corpses lay stretched on earth near to one another, the one
+captain of the Thracians and the other of the Epeans; and many
+another fell round them.
+</para>
+
+<para>
+And now no man would have made light of the fighting if he could
+have gone about among it scatheless and unwounded, with Minerva
+leading him by the hand, and protecting him from the storm of
+spears and arrows. For many Trojans and Achaeans on that day lay
+stretched side by side face downwards upon the earth.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK V</title>
+
+<para>
+Then Pallas Minerva put valour into the heart of Diomed, son of
+Tydeus, that he might excel all the other Argives, and cover
+himself with glory. She made a stream of fire flare from his
+shield and helmet like the star that shines most brilliantly in
+summer after its bath in the waters of Oceanus--even such a fire
+did she kindle upon his head and shoulders as she bade him speed
+into the thickest hurly-burly of the fight.
+</para>
+
+<para>
+Now there was a certain rich and honourable man among the
+Trojans, priest of Vulcan, and his name was Dares. He had two
+sons, Phegeus and Idaeus, both of them skilled in all the arts of
+war. These two came forward from the main body of Trojans, and
+set upon Diomed, he being on foot, while they fought from their
+chariot. When they were close up to one another, Phegeus took aim
+first, but his spear went over Diomed's left shoulder without
+hitting him. Diomed then threw, and his spear sped not in vain,
+for it hit Phegeus on the breast near the nipple, and he fell
+from his chariot. Idaeus did not dare to bestride his brother's
+body, but sprang from the chariot and took to flight, or he would
+have shared his brother's fate; whereon Vulcan saved him by
+wrapping him in a cloud of darkness, that his old father might
+not be utterly overwhelmed with grief; but the son of Tydeus
+drove off with the horses, and bade his followers take them to
+the ships. The Trojans were scared when they saw the two sons of
+Dares, one of them in fright and the other lying dead by his
+chariot. Minerva, therefore, took Mars by the hand and said,
+"Mars, Mars, bane of men, bloodstained stormer of cities, may we
+not now leave the Trojans and Achaeans to fight it out, and see
+to which of the two Jove will vouchsafe the victory? Let us go
+away, and thus avoid his anger."
+</para>
+
+<para>
+So saying, she drew Mars out of the battle, and set him down upon
+the steep banks of the Scamander. Upon this the Danaans drove the
+Trojans back, and each one of their chieftains killed his man.
+First King Agamemnon flung mighty Odius, captain of the Halizoni,
+from his chariot. The spear of Agamemnon caught him on the broad
+of his back, just as he was turning in flight; it struck him
+between the shoulders and went right through his chest, and his
+armour rang rattling round him as he fell heavily to the ground.
+</para>
+
+<para>
+Then Idomeneus killed Phaesus, son of Borus the Meonian, who had
+come from Varne. Mighty Idomeneus speared him on the right
+shoulder as he was mounting his chariot, and the darkness of
+death enshrouded him as he fell heavily from the car.
+</para>
+
+<para>
+The squires of Idomeneus spoiled him of his armour, while
+Menelaus, son of Atreus, killed Scamandrius the son of Strophius,
+a mighty huntsman and keen lover of the chase. Diana herself had
+taught him how to kill every kind of wild creature that is bred
+in mountain forests, but neither she nor his famed skill in
+archery could now save him, for the spear of Menelaus struck him
+in the back as he was flying; it struck him between the shoulders
+and went right through his chest, so that he fell headlong and
+his armour rang rattling round him.
+</para>
+
+<para>
+Meriones then killed Phereclus the son of Tecton, who was the son
+of Hermon, a man whose hand was skilled in all manner of cunning
+workmanship, for Pallas Minerva had dearly loved him. He it was
+that made the ships for Alexandrus, which were the beginning of
+all mischief, and brought evil alike both on the Trojans and on
+Alexandrus himself; for he heeded not the decrees of heaven.
+Meriones overtook him as he was flying, and struck him on the
+right buttock. The point of the spear went through the bone into
+the bladder, and death came upon him as he cried aloud and fell
+forward on his knees.
+</para>
+
+<para>
+Meges, moreover, slew Pedaeus, son of Antenor, who, though he was
+a bastard, had been brought up by Theano as one of her own
+children, for the love she bore her husband. The son of Phyleus
+got close up to him and drove a spear into the nape of his neck:
+it went under his tongue all among his teeth, so he bit the cold
+bronze, and fell dead in the dust.
+</para>
+
+<para>
+And Eurypylus, son of Euaemon, killed Hypsenor, the son of noble
+Dolopion, who had been made priest of the river Scamander, and
+was honoured among the people as though he were a god. Eurypylus
+gave him chase as he was flying before him, smote him with his
+sword upon the arm, and lopped his strong hand from off it. The
+bloody hand fell to the ground, and the shades of death, with
+fate that no man can withstand, came over his eyes.
+</para>
+
+<para>
+Thus furiously did the battle rage between them. As for the son
+of Tydeus, you could not say whether he was more among the
+Achaeans or the Trojans. He rushed across the plain like a winter
+torrent that has burst its barrier in full flood; no dykes, no
+walls of fruitful vineyards can embank it when it is swollen with
+rain from heaven, but in a moment it comes tearing onward, and
+lays many a field waste that many a strong man's hand has
+reclaimed--even so were the dense phalanxes of the Trojans driven
+in rout by the son of Tydeus, and many though they were, they
+dared not abide his onslaught.
+</para>
+
+<para>
+Now when the son of Lycaon saw him scouring the plain and driving
+the Trojans pell-mell before him, he aimed an arrow and hit the
+front part of his cuirass near the shoulder: the arrow went right
+through the metal and pierced the flesh, so that the cuirass was
+covered with blood. On this the son of Lycaon shouted in triumph,
+"Knights Trojans, come on; the bravest of the Achaeans is
+wounded, and he will not hold out much longer if King Apollo was
+indeed with me when I sped from Lycia hither."
+</para>
+
+<para>
+Thus did he vaunt; but his arrow had not killed Diomed, who
+withdrew and made for the chariot and horses of Sthenelus, the
+son of Capaneus. "Dear son of Capaneus," said he, "come down from
+your chariot, and draw the arrow out of my shoulder."
+</para>
+
+<para>
+Sthenelus sprang from his chariot, and drew the arrow from the
+wound, whereon the blood came spouting out through the hole that
+had been made in his shirt. Then Diomed prayed, saying, "Hear me,
+daughter of aegis-bearing Jove, unweariable, if ever you loved my
+father well and stood by him in the thick of a fight, do the like
+now by me; grant me to come within a spear's throw of that man
+and kill him. He has been too quick for me and has wounded me;
+and now he is boasting that I shall not see the light of the sun
+much longer."
+</para>
+
+<para>
+Thus he prayed, and Pallas Minerva heard him; she made his limbs
+supple and quickened his hands and his feet. Then she went up
+close to him and said, "Fear not, Diomed, to do battle with the
+Trojans, for I have set in your heart the spirit of your knightly
+father Tydeus. Moreover, I have withdrawn the veil from your
+eyes, that you know gods and men apart. If, then, any other god
+comes here and offers you battle, do not fight him; but should
+Jove's daughter Venus come, strike her with your spear and wound
+her."
+</para>
+
+<para>
+When she had said this Minerva went away, and the son of Tydeus
+again took his place among the foremost fighters, three times
+more fierce even than he had been before. He was like a lion that
+some mountain shepherd has wounded, but not killed, as he is
+springing over the wall of a sheep-yard to attack the sheep. The
+shepherd has roused the brute to fury but cannot defend his
+flock, so he takes shelter under cover of the buildings, while
+the sheep, panic-stricken on being deserted, are smothered in
+heaps one on top of the other, and the angry lion leaps out over
+the sheep-yard wall. Even thus did Diomed go furiously about
+among the Trojans.
+</para>
+
+<para>
+He killed Astynous, and Hypeiron shepherd of his people, the one
+with a thrust of his spear, which struck him above the nipple,
+the other with a sword-cut on the collar-bone, that severed his
+shoulder from his neck and back. He let both of them lie, and
+went in pursuit of Abas and Polyidus, sons of the old reader of
+dreams Eurydamas: they never came back for him to read them any
+more dreams, for mighty Diomed made an end of them. He then gave
+chase to Xanthus and Thoon, the two sons of Phaenops, both of
+them very dear to him, for he was now worn out with age, and
+begat no more sons to inherit his possessions. But Diomed took
+both their lives and left their father sorrowing bitterly, for he
+nevermore saw them come home from battle alive, and his kinsmen
+divided his wealth among themselves.
+</para>
+
+<para>
+Then he came upon two sons of Priam, Echemmon and Chromius, as
+they were both in one chariot. He sprang upon them as a lion
+fastens on the neck of some cow or heifer when the herd is
+feeding in a coppice. For all their vain struggles he flung them
+both from their chariot and stripped the armour from their
+bodies. Then he gave their horses to his comrades to take them
+back to the ships.
+</para>
+
+<para>
+When Aeneas saw him thus making havoc among the ranks, he went
+through the fight amid the rain of spears to see if he could find
+Pandarus. When he had found the brave son of Lycaon he said,
+"Pandarus, where is now your bow, your winged arrows, and your
+renown as an archer, in respect of which no man here can rival
+you nor is there any in Lycia that can beat you? Lift then your
+hands to Jove and send an arrow at this fellow who is going so
+masterfully about, and has done such deadly work among the
+Trojans. He has killed many a brave man--unless indeed he is some
+god who is angry with the Trojans about their sacrifices, and and
+has set his hand against them in his displeasure."
+</para>
+
+<para>
+And the son of Lycaon answered, "Aeneas, I take him for none
+other than the son of Tydeus. I know him by his shield, the visor
+of his helmet, and by his horses. It is possible that he may be a
+god, but if he is the man I say he is, he is not making all this
+havoc without heaven's help, but has some god by his side who is
+shrouded in a cloud of darkness, and who turned my arrow aside
+when it had hit him. I have taken aim at him already and hit him
+on the right shoulder; my arrow went through the breastpiece of
+his cuirass; and I made sure I should send him hurrying to the
+world below, but it seems that I have not killed him. There must
+be a god who is angry with me. Moreover I have neither horse nor
+chariot. In my father's stables there are eleven excellent
+chariots, fresh from the builder, quite new, with cloths spread
+over them; and by each of them there stand a pair of horses,
+champing barley and rye; my old father Lycaon urged me again and
+again when I was at home and on the point of starting, to take
+chariots and horses with me that I might lead the Trojans in
+battle, but I would not listen to him; it would have been much
+better if I had done so, but I was thinking about the horses,
+which had been used to eat their fill, and I was afraid that in
+such a great gathering of men they might be ill-fed, so I left
+them at home and came on foot to Ilius armed only with my bow and
+arrows. These it seems, are of no use, for I have already hit two
+chieftains, the sons of Atreus and of Tydeus, and though I drew
+blood surely enough, I have only made them still more furious. I
+did ill to take my bow down from its peg on the day I led my band
+of Trojans to Ilius in Hector's service, and if ever I get home
+again to set eyes on my native place, my wife, and the greatness
+of my house, may some one cut my head off then and there if I do
+not break the bow and set it on a hot fire--such pranks as it
+plays me."
+</para>
+
+<para>
+Aeneas answered, "Say no more. Things will not mend till we two
+go against this man with chariot and horses and bring him to a
+trial of arms. Mount my chariot, and note how cleverly the horses
+of Tros can speed hither and thither over the plain in pursuit or
+flight. If Jove again vouchsafes glory to the son of Tydeus they
+will carry us safely back to the city. Take hold, then, of the
+whip and reins while I stand upon the car to fight, or else do
+you wait this man's onset while I look after the horses."
+</para>
+
+<para>
+"Aeneas," replied the son of Lycaon, "take the reins and drive;
+if we have to fly before the son of Tydeus the horses will go
+better for their own driver. If they miss the sound of your voice
+when they expect it they may be frightened, and refuse to take us
+out of the fight. The son of Tydeus will then kill both of us and
+take the horses. Therefore drive them yourself and I will be
+ready for him with my spear."
+</para>
+
+<para>
+They then mounted the chariot and drove full-speed towards the
+son of Tydeus. Sthenelus, son of Capaneus, saw them coming and
+said to Diomed, "Diomed, son of Tydeus, man after my own heart, I
+see two heroes speeding towards you, both of them men of might
+the one a skilful archer, Pandarus son of Lycaon, the other,
+Aeneas, whose sire is Anchises, while his mother is Venus. Mount
+the chariot and let us retreat. Do not, I pray you, press so
+furiously forward, or you may get killed."
+</para>
+
+<para>
+Diomed looked angrily at him and answered: "Talk not of flight,
+for I shall not listen to you: I am of a race that knows neither
+flight nor fear, and my limbs are as yet unwearied. I am in no
+mind to mount, but will go against them even as I am; Pallas
+Minerva bids me be afraid of no man, and even though one of them
+escape, their steeds shall not take both back again. I say
+further, and lay my saying to your heart--if Minerva sees fit to
+vouchsafe me the glory of killing both, stay your horses here and
+make the reins fast to the rim of the chariot; then be sure you
+spring Aeneas' horses and drive them from the Trojan to the
+Achaean ranks. They are of the stock that great Jove gave to Tros
+in payment for his son Ganymede, and are the finest that live and
+move under the sun. King Anchises stole the blood by putting his
+mares to them without Laomedon's knowledge, and they bore him six
+foals. Four are still in his stables, but he gave the other two
+to Aeneas. We shall win great glory if we can take them."
+</para>
+
+<para>
+Thus did they converse, but the other two had now driven close up
+to them, and the son of Lycaon spoke first. "Great and mighty
+son," said he, "of noble Tydeus, my arrow failed to lay you low,
+so I will now try with my spear."
+</para>
+
+<para>
+He poised his spear as he spoke and hurled it from him. It struck
+the shield of the son of Tydeus; the bronze point pierced it and
+passed on till it reached the breastplate. Thereon the son of
+Lycaon shouted out and said, "You are hit clean through the
+belly; you will not stand out for long, and the glory of the
+fight is mine."
+</para>
+
+<para>
+But Diomed all undismayed made answer, "You have missed, not hit,
+and before you two see the end of this matter one or other of you
+shall glut tough-shielded Mars with his blood."
+</para>
+
+<para>
+With this he hurled his spear, and Minerva guided it on to
+Pandarus's nose near the eye. It went crashing in among his white
+teeth; the bronze point cut through the root of his tongue,
+coming out under his chin, and his glistening armour rang
+rattling round him as he fell heavily to the ground. The horses
+started aside for fear, and he was reft of life and strength.
+</para>
+
+<para>
+Aeneas sprang from his chariot armed with shield and spear,
+fearing lest the Achaeans should carry off the body. He bestrode
+it as a lion in the pride of strength, with shield and spear
+before him and a cry of battle on his lips resolute to kill the
+first that should dare face him. But the son of Tydeus caught up
+a mighty stone, so huge and great that as men now are it would
+take two to lift it; nevertheless he bore it aloft with ease
+unaided, and with this he struck Aeneas on the groin where the
+hip turns in the joint that is called the "cup-bone." The stone
+crushed this joint, and broke both the sinews, while its jagged
+edges tore away all the flesh. The hero fell on his knees, and
+propped himself with his hand resting on the ground till the
+darkness of night fell upon his eyes. And now Aeneas, king of
+men, would have perished then and there, had not his mother,
+Jove's daughter Venus, who had conceived him by Anchises when he
+was herding cattle, been quick to mark, and thrown her two white
+arms about the body of her dear son. She protected him by
+covering him with a fold of her own fair garment, lest some
+Danaan should drive a spear into his breast and kill him.
+</para>
+
+<para>
+Thus, then, did she bear her dear son out of the fight. But the
+son of Capaneus was not unmindful of the orders that Diomed had
+given him. He made his own horses fast, away from the
+hurly-burly, by binding the reins to the rim of the chariot. Then
+he sprang upon Aeneas's horses and drove them from the Trojan to
+the Achaean ranks. When he had so done he gave them over to his
+chosen comrade Deipylus, whom he valued above all others as the
+one who was most like-minded with himself, to take them on to the
+ships. He then remounted his own chariot, seized the reins, and
+drove with all speed in search of the son of Tydeus.
+</para>
+
+<para>
+Now the son of Tydeus was in pursuit of the Cyprian goddess,
+spear in hand, for he knew her to be feeble and not one of those
+goddesses that can lord it among men in battle like Minerva or
+Enyo the waster of cities, and when at last after a long chase he
+caught her up, he flew at her and thrust his spear into the flesh
+of her delicate hand. The point tore through the ambrosial robe
+which the Graces had woven for her, and pierced the skin between
+her wrist and the palm of her hand, so that the immortal blood,
+or ichor, that flows in the veins of the blessed gods, came
+pouring from the wound; for the gods do not eat bread nor drink
+wine, hence they have no blood such as ours, and are immortal.
+Venus screamed aloud, and let her son fall, but Phoebus Apollo
+caught him in his arms, and hid him in a cloud of darkness, lest
+some Danaan should drive a spear into his breast and kill him;
+and Diomed shouted out as he left her, "Daughter of Jove, leave
+war and battle alone, can you not be contented with beguiling
+silly women? If you meddle with fighting you will get what will
+make you shudder at the very name of war."
+</para>
+
+<para>
+The goddess went dazed and discomfited away, and Iris, fleet as
+the wind, drew her from the throng, in pain and with her fair
+skin all besmirched. She found fierce Mars waiting on the left of
+the battle, with his spear and his two fleet steeds resting on a
+cloud; whereon she fell on her knees before her brother and
+implored him to let her have his horses. "Dear brother," she
+cried, "save me, and give me your horses to take me to Olympus
+where the gods dwell. I am badly wounded by a mortal, the son of
+Tydeus, who would now fight even with father Jove."
+</para>
+
+<para>
+Thus she spoke, and Mars gave her his gold-bedizened steeds. She
+mounted the chariot sick and sorry at heart, while Iris sat
+beside her and took the reins in her hand. She lashed her horses
+on and they flew forward nothing loth, till in a trice they were
+at high Olympus, where the gods have their dwelling. There she
+stayed them, unloosed them from the chariot, and gave them their
+ambrosial forage; but Venus flung herself on to the lap of her
+mother Dione, who threw her arms about her and caressed her,
+saying, "Which of the heavenly beings has been treating you in
+this way, as though you had been doing something wrong in the
+face of day?"
+</para>
+
+<para>
+And laughter-loving Venus answered, "Proud Diomed, the son of
+Tydeus, wounded me because I was bearing my dear son Aeneas, whom
+I love best of all mankind, out of the fight. The war is no
+longer one between Trojans and Achaeans, for the Danaans have now
+taken to fighting with the immortals."
+</para>
+
+<para>
+"Bear it, my child," replied Dione, "and make the best of it. We
+dwellers in Olympus have to put up with much at the hands of men,
+and we lay much suffering on one another. Mars had to suffer when
+Otus and Ephialtes, children of Aloeus, bound him in cruel bonds,
+so that he lay thirteen months imprisoned in a vessel of bronze.
+Mars would have then perished had not fair Eeriboea, stepmother
+to the sons of Aloeus, told Mercury, who stole him away when he
+was already well-nigh worn out by the severity of his bondage.
+Juno, again, suffered when the mighty son of Amphitryon wounded
+her on the right breast with a three-barbed arrow, and nothing
+could assuage her pain. So, also, did huge Hades, when this same
+man, the son of aegis-bearing Jove, hit him with an arrow even at
+the gates of hell, and hurt him badly. Thereon Hades went to the
+house of Jove on great Olympus, angry and full of pain; and the
+arrow in his brawny shoulder caused him great anguish till Paeeon
+healed him by spreading soothing herbs on the wound, for Hades
+was not of mortal mould. Daring, head-strong, evildoer who recked
+not of his sin in shooting the gods that dwell in Olympus. And
+now Minerva has egged this son of Tydeus on against yourself,
+fool that he is for not reflecting that no man who fights with
+gods will live long or hear his children prattling about his
+knees when he returns from battle. Let, then, the son of Tydeus
+see that he does not have to fight with one who is stronger than
+you are. Then shall his brave wife Aegialeia, daughter of
+Adrestus, rouse her whole house from sleep, wailing for the loss
+of her wedded lord, Diomed the bravest of the Achaeans."
+</para>
+
+<para>
+So saying, she wiped the ichor from the wrist of her daughter
+with both hands, whereon the pain left her, and her hand was
+healed. But Minerva and Juno, who were looking on, began to taunt
+Jove with their mocking talk, and Minerva was first to speak.
+"Father Jove," said she, "do not be angry with me, but I think
+the Cyprian must have been persuading some one of the Achaean
+women to go with the Trojans of whom she is so very fond, and
+while caressing one or other of them she must have torn her
+delicate hand with the gold pin of the woman's brooch."
+</para>
+
+<para>
+The sire of gods and men smiled, and called golden Venus to his
+side. "My child," said he, "it has not been given you to be a
+warrior. Attend, henceforth, to your own delightful matrimonial
+duties, and leave all this fighting to Mars and to Minerva."
+</para>
+
+<para>
+Thus did they converse. But Diomed sprang upon Aeneas, though he
+knew him to be in the very arms of Apollo. Not one whit did he
+fear the mighty god, so set was he on killing Aeneas and
+stripping him of his armour. Thrice did he spring forward with
+might and main to slay him, and thrice did Apollo beat back his
+gleaming shield. When he was coming on for the fourth time, as
+though he were a god, Apollo shouted to him with an awful voice
+and said, "Take heed, son of Tydeus, and draw off; think not to
+match yourself against gods, for men that walk the earth cannot
+hold their own with the immortals."
+</para>
+
+<para>
+The son of Tydeus then gave way for a little space, to avoid the
+anger of the god, while Apollo took Aeneas out of the crowd and
+set him in sacred Pergamus, where his temple stood. There, within
+the mighty sanctuary, Latona and Diana healed him and made him
+glorious to behold, while Apollo of the silver bow fashioned a
+wraith in the likeness of Aeneas, and armed as he was. Round this
+the Trojans and Achaeans hacked at the bucklers about one
+another's breasts, hewing each other's round shields and light
+hide-covered targets. Then Phoebus Apollo said to Mars, "Mars,
+Mars, bane of men, blood-stained stormer of cities, can you not
+go to this man, the son of Tydeus, who would now fight even with
+father Jove, and draw him out of the battle? He first went up to
+the Cyprian and wounded her in the hand near her wrist, and
+afterwards sprang upon me too, as though he were a god."
+</para>
+
+<para>
+He then took his seat on the top of Pergamus, while murderous
+Mars went about among the ranks of the Trojans, cheering them on,
+in the likeness of fleet Acamas chief of the Thracians. "Sons of
+Priam," said he, "how long will you let your people be thus
+slaughtered by the Achaeans? Would you wait till they are at the
+walls of Troy? Aeneas the son of Anchises has fallen, he whom we
+held in as high honour as Hector himself. Help me, then, to
+rescue our brave comrade from the stress of the fight."
+</para>
+
+<para>
+With these words he put heart and soul into them all. Then
+Sarpedon rebuked Hector very sternly. "Hector," said he, "where
+is your prowess now? You used to say that though you had neither
+people nor allies you could hold the town alone with your
+brothers and brothers-in-law. I see not one of them here; they
+cower as hounds before a lion; it is we, your allies, who bear
+the brunt of the battle. I have come from afar, even from Lycia
+and the banks of the river Xanthus, where I have left my wife, my
+infant son, and much wealth to tempt whoever is needy;
+nevertheless, I head my Lycian soldiers and stand my ground
+against any who would fight me though I have nothing here for the
+Achaeans to plunder, while you look on, without even bidding your
+men stand firm in defence of their wives. See that you fall not
+into the hands of your foes as men caught in the meshes of a net,
+and they sack your fair city forthwith. Keep this before your
+mind night and day, and beseech the captains of your allies to
+hold on without flinching, and thus put away their reproaches
+from you."
+</para>
+
+<para>
+So spoke Sarpedon, and Hector smarted under his words. He sprang
+from his chariot clad in his suit of armour, and went about among
+the host brandishing his two spears, exhorting the men to fight
+and raising the terrible cry of battle. Then they rallied and
+again faced the Achaeans, but the Argives stood compact and firm,
+and were not driven back. As the breezes sport with the chaff
+upon some goodly threshing-floor, when men are winnowing--while
+yellow Ceres blows with the wind to sift the chaff from the
+grain, and the chaff-heaps grow whiter and whiter--even so did
+the Achaeans whiten in the dust which the horses' hoofs raised to
+the firmament of heaven, as their drivers turned them back to
+battle, and they bore down with might upon the foe. Fierce Mars,
+to help the Trojans, covered them in a veil of darkness, and went
+about everywhere among them, inasmuch as Phoebus Apollo had told
+him that when he saw Pallas, Minerva leave the fray he was to put
+courage into the hearts of the Trojans--for it was she who was
+helping the Danaans. Then Apollo sent Aeneas forth from his rich
+sanctuary, and filled his heart with valour, whereon he took his
+place among his comrades, who were overjoyed at seeing him alive,
+sound, and of a good courage; but they could not ask him how it
+had all happened, for they were too busy with the turmoil raised
+by Mars and by Strife, who raged insatiably in their midst.
+</para>
+
+<para>
+The two Ajaxes, Ulysses and Diomed, cheered the Danaans on,
+fearless of the fury and onset of the Trojans. They stood as
+still as clouds which the son of Saturn has spread upon the
+mountain tops when there is no air and fierce Boreas sleeps with
+the other boisterous winds whose shrill blasts scatter the clouds
+in all directions--even so did the Danaans stand firm and
+unflinching against the Trojans. The son of Atreus went about
+among them and exhorted them. "My friends," said he, "quit
+yourselves like brave men, and shun dishonour in one another's
+eyes amid the stress of battle. They that shun dishonour more
+often live than get killed, but they that fly save neither life
+nor name."
+</para>
+
+<para>
+As he spoke he hurled his spear and hit one of those who were in
+the front rank, the comrade of Aeneas, Deicoon son of Pergasus,
+whom the Trojans held in no less honour than the sons of Priam,
+for he was ever quick to place himself among the foremost. The
+spear of King Agamemnon struck his shield and went right through
+it, for the shield stayed it not. It drove through his belt into
+the lower part of his belly, and his armour rang rattling round
+him as he fell heavily to the ground.
+</para>
+
+<para>
+Then Aeneas killed two champions of the Danaans, Crethon and
+Orsilochus. Their father was a rich man who lived in the strong
+city of Phere and was descended from the river Alpheus, whose
+broad stream flows through the land of the Pylians. The river
+begat Orsilochus, who ruled over much people and was father to
+Diocles, who in his turn begat twin sons, Crethon and Orsilochus,
+well skilled in all the arts of war. These, when they grew up,
+went to Ilius with the Argive fleet in the cause of Menelaus and
+Agamemnon sons of Atreus, and there they both of them fell. As
+two lions whom their dam has reared in the depths of some
+mountain forest to plunder homesteads and carry off sheep and
+cattle till they get killed by the hand of man, so were these two
+vanquished by Aeneas, and fell like high pine-trees to the
+ground.
+</para>
+
+<para>
+Brave Menelaus pitied them in their fall, and made his way to the
+front, clad in gleaming bronze and brandishing his spear, for
+Mars egged him on to do so with intent that he should be killed
+by Aeneas; but Antilochus the son of Nestor saw him and sprang
+forward, fearing that the king might come to harm and thus bring
+all their labour to nothing; when, therefore Aeneas and Menelaus
+were setting their hands and spears against one another eager to
+do battle, Antilochus placed himself by the side of Menelaus.
+Aeneas, bold though he was, drew back on seeing the two heroes
+side by side in front of him, so they drew the bodies of Crethon
+and Orsilochus to the ranks of the Achaeans and committed the two
+poor fellows into the hands of their comrades. They then turned
+back and fought in the front ranks.
+</para>
+
+<para>
+They killed Pylaemenes peer of Mars, leader of the Paphlagonian
+warriors. Menelaus struck him on the collar-bone as he was
+standing on his chariot, while Antilochus hit his charioteer and
+squire Mydon, the son of Atymnius, who was turning his horses in
+flight. He hit him with a stone upon the elbow, and the reins,
+enriched with white ivory, fell from his hands into the dust.
+Antilochus rushed towards him and struck him on the temples with
+his sword, whereon he fell head first from the chariot to the
+ground. There he stood for a while with his head and shoulders
+buried deep in the dust--for he had fallen on sandy soil till his
+horses kicked him and laid him flat on the ground, as Antilochus
+lashed them and drove them off to the host of the Achaeans.
+</para>
+
+<para>
+But Hector marked them from across the ranks, and with a loud cry
+rushed towards them, followed by the strong battalions of the
+Trojans. Mars and dread Enyo led them on, she fraught with
+ruthless turmoil of battle, while Mars wielded a monstrous spear,
+and went about, now in front of Hector and now behind him.
+</para>
+
+<para>
+Diomed shook with passion as he saw them. As a man crossing a
+wide plain is dismayed to find himself on the brink of some great
+river rolling swiftly to the sea--he sees its boiling waters and
+starts back in fear--even so did the son of Tydeus give ground.
+Then he said to his men, "My friends, how can we wonder that
+Hector wields the spear so well? Some god is ever by his side to
+protect him, and now Mars is with him in the likeness of mortal
+man. Keep your faces therefore towards the Trojans, but give
+ground backwards, for we dare not fight with gods."
+</para>
+
+<para>
+As he spoke the Trojans drew close up, and Hector killed two men,
+both in one chariot, Menesthes and Anchialus, heroes well versed
+in war. Ajax son of Telamon pitied them in their fall; he came
+close up and hurled his spear, hitting Amphius the son of
+Selagus, a man of great wealth who lived in Paesus and owned much
+corn-growing land, but his lot had led him to come to the aid of
+Priam and his sons. Ajax struck him in the belt; the spear
+pierced the lower part of his belly, and he fell heavily to the
+ground. Then Ajax ran towards him to strip him of his armour, but
+the Trojans rained spears upon him, many of which fell upon his
+shield. He planted his heel upon the body and drew out his spear,
+but the darts pressed so heavily upon him that he could not strip
+the goodly armour from his shoulders. The Trojan chieftains,
+moreover, many and valiant, came about him with their spears, so
+that he dared not stay; great, brave and valiant though he was,
+they drove him from them and he was beaten back.
+</para>
+
+<para>
+Thus, then, did the battle rage between them. Presently the
+strong hand of fate impelled Tlepolemus, the son of Hercules, a
+man both brave and of great stature, to fight Sarpedon; so the
+two, son and grandson of great Jove, drew near to one another,
+and Tlepolemus spoke first. "Sarpedon," said he, "councillor of
+the Lycians, why should you come skulking here you who are a man
+of peace? They lie who call you son of aegis-bearing Jove, for
+you are little like those who were of old his children. Far other
+was Hercules, my own brave and lion-hearted father, who came here
+for the horses of Laomedon, and though he had six ships only, and
+few men to follow him, sacked the city of Ilius and made a
+wilderness of her highways. You are a coward, and your people are
+falling from you. For all your strength, and all your coming from
+Lycia, you will be no help to the Trojans but will pass the gates
+of Hades vanquished by my hand."
+</para>
+
+<para>
+And Sarpedon, captain of the Lycians, answered, "Tlepolemus, your
+father overthrew Ilius by reason of Laomedon's folly in refusing
+payment to one who had served him well. He would not give your
+father the horses which he had come so far to fetch. As for
+yourself, you shall meet death by my spear. You shall yield glory
+to myself, and your soul to Hades of the noble steeds."
+</para>
+
+<para>
+Thus spoke Sarpedon, and Tlepolemus upraised his spear. They
+threw at the same moment, and Sarpedon struck his foe in the
+middle of his throat; the spear went right through, and the
+darkness of death fell upon his eyes. Tlepolemus's spear struck
+Sarpedon on the left thigh with such force that it tore through
+the flesh and grazed the bone, but his father as yet warded off
+destruction from him.
+</para>
+
+<para>
+His comrades bore Sarpedon out of the fight, in great pain by the
+weight of the spear that was dragging from his wound. They were
+in such haste and stress as they bore him that no one thought of
+drawing the spear from his thigh so as to let him walk uprightly.
+Meanwhile the Achaeans carried off the body of Tlepolemus,
+whereon Ulysses was moved to pity, and panted for the fray as he
+beheld them. He doubted whether to pursue the son of Jove, or to
+make slaughter of the Lycian rank and file; it was not decreed,
+however, that he should slay the son of Jove; Minerva, therefore,
+turned him against the main body of the Lycians. He killed
+Coeranus, Alastor, Chromius, Alcandrus, Halius, Noemon, and
+Prytanis, and would have slain yet more, had not great Hector
+marked him, and sped to the front of the fight clad in his suit
+of mail, filling the Danaans with terror. Sarpedon was glad when
+he saw him coming, and besought him, saying, "Son of Priam, let
+me not be here to fall into the hands of the Danaans. Help me,
+and since I may not return home to gladden the hearts of my wife
+and of my infant son, let me die within the walls of your city."
+</para>
+
+<para>
+Hector made him no answer, but rushed onward to fall at once upon
+the Achaeans and kill many among them. His comrades then bore
+Sarpedon away and laid him beneath Jove's spreading oak tree.
+Pelagon, his friend and comrade, drew the spear out of his thigh,
+but Sarpedon fainted and a mist came over his eyes. Presently he
+came to himself again, for the breath of the north wind as it
+played upon him gave him new life, and brought him out of the
+deep swoon into which he had fallen.
+</para>
+
+<para>
+Meanwhile the Argives were neither driven towards their ships by
+Mars and Hector, nor yet did they attack them; when they knew
+that Mars was with the Trojans they retreated, but kept their
+faces still turned towards the foe. Who, then, was first and who
+last to be slain by Mars and Hector? They were valiant Teuthras,
+and Orestes the renowned charioteer, Trechus the Aetolian
+warrior, Oenomaus, Helenus the son of Oenops, and Oresbius of the
+gleaming girdle, who was possessed of great wealth, and dwelt by
+the Cephisian lake with the other Boeotians who lived near him,
+owners of a fertile country.
+</para>
+
+<para>
+Now when the goddess Juno saw the Argives thus falling, she said
+to Minerva, "Alas, daughter of aegis-bearing Jove, unweariable,
+the promise we made Menelaus that he should not return till he
+had sacked the city of Ilius will be of no effect if we let Mars
+rage thus furiously. Let us go into the fray at once."
+</para>
+
+<para>
+Minerva did not gainsay her. Thereon the august goddess, daughter
+of great Saturn, began to harness her gold-bedizened steeds. Hebe
+with all speed fitted on the eight-spoked wheels of bronze that
+were on either side of the iron axle-tree. The felloes of the
+wheels were of gold, imperishable, and over these there was a
+tire of bronze, wondrous to behold. The naves of the wheels were
+silver, turning round the axle upon either side. The car itself
+was made with plaited bands of gold and silver, and it had a
+double top-rail running all round it. From the body of the car
+there went a pole of silver, on to the end of which she bound the
+golden yoke, with the bands of gold that were to go under the
+necks of the horses Then Juno put her steeds under the yoke,
+eager for battle and the war-cry.
+</para>
+
+<para>
+Meanwhile Minerva flung her richly embroidered vesture, made with
+her own hands, on to her father's threshold, and donned the shirt
+of Jove, arming herself for battle. She threw her tasselled aegis
+about her shoulders, wreathed round with Rout as with a fringe,
+and on it were Strife, and Strength, and Panic whose blood runs
+cold; moreover there was the head of the dread monster Gorgon,
+grim and awful to behold, portent of aegis-bearing Jove. On her
+head she set her helmet of gold, with four plumes, and coming to
+a peak both in front and behind--decked with the emblems of a
+hundred cities; then she stepped into her flaming chariot and
+grasped the spear, so stout and sturdy and strong, with which she
+quells the ranks of heroes who have displeased her. Juno lashed
+the horses on, and the gates of heaven bellowed as they flew open
+of their own accord--gates over which the Hours preside, in whose
+hands are Heaven and Olympus, either to open the dense cloud that
+hides them, or to close it. Through these the goddesses drove
+their obedient steeds, and found the son of Saturn sitting all
+alone on the topmost ridges of Olympus. There Juno stayed her
+horses, and spoke to Jove the son of Saturn, lord of all. "Father
+Jove," said she, "are you not angry with Mars for these high
+doings? how great and goodly a host of the Achaeans he has
+destroyed to my great grief, and without either right or reason,
+while the Cyprian and Apollo are enjoying it all at their ease
+and setting this unrighteous madman on to do further mischief. I
+hope, Father Jove, that you will not be angry if I hit Mars hard,
+and chase him out of the battle."
+</para>
+
+<para>
+And Jove answered, "Set Minerva on to him, for she punishes him
+more often than any one else does."
+</para>
+
+<para>
+Juno did as he had said. She lashed her horses, and they flew
+forward nothing loth midway betwixt earth and sky. As far as a
+man can see when he looks out upon the sea from some high beacon,
+so far can the loud-neighing horses of the gods spring at a
+single bound. When they reached Troy and the place where its two
+flowing streams Simois and Scamander meet, there Juno stayed them
+and took them from the chariot. She hid them in a thick cloud,
+and Simois made ambrosia spring up for them to eat; the two
+goddesses then went on, flying like turtledoves in their
+eagerness to help the Argives. When they came to the part where
+the bravest and most in number were gathered about mighty Diomed,
+fighting like lions or wild boars of great strength and
+endurance, there Juno stood still and raised a shout like that of
+brazen-voiced Stentor, whose cry was as loud as that of fifty men
+together. "Argives," she cried; "shame on cowardly creatures,
+brave in semblance only; as long as Achilles was fighting, if his
+spear was so deadly that the Trojans dared not show themselves
+outside the Dardanian gates, but now they sally far from the city
+and fight even at your ships."
+</para>
+
+<para>
+With these words she put heart and soul into them all, while
+Minerva sprang to the side of the son of Tydeus, whom she found
+near his chariot and horses, cooling the wound that Pandarus had
+given him. For the sweat caused by the hand that bore the weight
+of his shield irritated the hurt: his arm was weary with pain,
+and he was lifting up the strap to wipe away the blood. The
+goddess laid her hand on the yoke of his horses and said, "The
+son of Tydeus is not such another as his father. Tydeus was a
+little man, but he could fight, and rushed madly into the fray
+even when I told him not to do so. When he went all unattended as
+envoy to the city of Thebes among the Cadmeans, I bade him feast
+in their houses and be at peace; but with that high spirit which
+was ever present with him, he challenged the youth of the
+Cadmeans, and at once beat them in all that he attempted, so
+mightily did I help him. I stand by you too to protect you, and I
+bid you be instant in fighting the Trojans; but either you are
+tired out, or you are afraid and out of heart, and in that case I
+say that you are no true son of Tydeus the son of Oeneus."
+</para>
+
+<para>
+Diomed answered, "I know you, goddess, daughter of aegis-bearing
+Jove, and will hide nothing from you. I am not afraid nor out of
+heart, nor is there any slackness in me. I am only following your
+own instructions; you told me not to fight any of the blessed
+gods; but if Jove's daughter Venus came into battle I was to
+wound her with my spear. Therefore I am retreating, and bidding
+the other Argives gather in this place, for I know that Mars is
+now lording it in the field."
+</para>
+
+<para>
+"Diomed, son of Tydeus," replied Minerva, "man after my own
+heart, fear neither Mars nor any other of the immortals, for I
+will befriend you. Nay, drive straight at Mars, and smite him in
+close combat; fear not this raging madman, villain incarnate,
+first on one side and then on the other. But now he was holding
+talk with Juno and myself, saying he would help the Argives and
+attack the Trojans; nevertheless he is with the Trojans, and has
+forgotten the Argives."
+</para>
+
+<para>
+With this she caught hold of Sthenelus and lifted him off the
+chariot on to the ground. In a second he was on the ground,
+whereupon the goddess mounted the car and placed herself by the
+side of Diomed. The oaken axle groaned aloud under the burden of
+the awful goddess and the hero; Pallas Minerva took the whip and
+reins, and drove straight at Mars. He was in the act of stripping
+huge Periphas, son of Ochesius and bravest of the Aetolians.
+Bloody Mars was stripping him of his armour, and Minerva donned
+the helmet of Hades, that he might not see her; when, therefore,
+he saw Diomed, he made straight for him and let Periphas lie
+where he had fallen. As soon as they were at close quarters he
+let fly with his bronze spear over the reins and yoke, thinking
+to take Diomed's life, but Minerva caught the spear in her hand
+and made it fly harmlessly over the chariot. Diomed then threw,
+and Pallas Minerva drove the spear into the pit of Mars's stomach
+where his under-girdle went round him. There Diomed wounded him,
+tearing his fair flesh and then drawing his spear out again. Mars
+roared as loudly as nine or ten thousand men in the thick of a
+fight, and the Achaeans and Trojans were struck with panic, so
+terrible was the cry he raised.
+</para>
+
+<para>
+As a dark cloud in the sky when it comes on to blow after heat,
+even so did Diomed son of Tydeus see Mars ascend into the broad
+heavens. With all speed he reached high Olympus, home of the
+gods, and in great pain sat down beside Jove the son of Saturn.
+He showed Jove the immortal blood that was flowing from his
+wound, and spoke piteously, saying, "Father Jove, are you not
+angered by such doings? We gods are continually suffering in the
+most cruel manner at one another's hands while helping mortals;
+and we all owe you a grudge for having begotten that mad
+termagant of a daughter, who is always committing outrage of some
+kind. We other gods must all do as you bid us, but her you
+neither scold nor punish; you encourage her because the pestilent
+creature is your daughter. See how she has been inciting proud
+Diomed to vent his rage on the immortal gods. First he went up to
+the Cyprian and wounded her in the hand near her wrist, and then
+he sprang upon me too as though he were a god. Had I not run for
+it I must either have lain there for long enough in torments
+among the ghastly corpes, or have been eaten alive with spears
+till I had no more strength left in me."
+</para>
+
+<para>
+Jove looked angrily at him and said, "Do not come whining here,
+Sir Facing-both-ways. I hate you worst of all the gods in
+Olympus, for you are ever fighting and making mischief. You have
+the intolerable and stubborn spirit of your mother Juno: it is
+all I can do to manage her, and it is her doing that you are now
+in this plight: still, I cannot let you remain longer in such
+great pain; you are my own offspring, and it was by me that your
+mother conceived you; if, however, you had been the son of any
+other god, you are so destructive that by this time you should
+have been lying lower than the Titans."
+</para>
+
+<para>
+He then bade Paeeon heal him, whereon Paeeon spread pain-killing
+herbs upon his wound and cured him, for he was not of mortal
+mould. As the juice of the fig-tree curdles milk, and thickens it
+in a moment though it is liquid, even so instantly did Paeeon
+cure fierce Mars. Then Hebe washed him, and clothed him in goodly
+raiment, and he took his seat by his father Jove all glorious to
+behold.
+</para>
+
+<para>
+But Juno of Argos and Minerva of Alalcomene, now that they had
+put a stop to the murderous doings of Mars, went back again to
+the house of Jove.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK VI</title>
+
+<para>
+THE fight between Trojans and Achaeans was now left to rage as it
+would, and the tide of war surged hither and thither over the
+plain as they aimed their bronze-shod spears at one another
+between the streams of Simois and Xanthus.
+</para>
+
+<para>
+First, Ajax son of Telamon, tower of strength to the Achaeans,
+broke a phalanx of the Trojans, and came to the assistance of his
+comrades by killing Acamas son of Eussorus, the best man among
+the Thracians, being both brave and of great stature. The spear
+struck the projecting peak of his helmet: its bronze point then
+went through his forehead into the brain, and darkness veiled his
+eyes.
+</para>
+
+<para>
+Then Diomed killed Axylus son of Teuthranus, a rich man who lived
+in the strong city of Arisbe, and was beloved by all men; for he
+had a house by the roadside, and entertained every one who
+passed; howbeit not one of his guests stood before him to save
+his life, and Diomed killed both him and his squire Calesius, who
+was then his charioteer--so the pair passed beneath the earth.
+</para>
+
+<para>
+Euryalus killed Dresus and Opheltius, and then went in pursuit of
+Aesepus and Pedasus, whom the naiad nymph Abarbarea had borne to
+noble Bucolion. Bucolion was eldest son to Laomedon, but he was a
+bastard. While tending his sheep he had converse with the nymph,
+and she conceived twin sons; these the son of Mecisteus now slew,
+and he stripped the armour from their shoulders. Polypoetes then
+killed Astyalus, Ulysses Pidytes of Percote, and Teucer Aretaon.
+Ablerus fell by the spear of Nestor's son Antilochus, and
+Agamemnon, king of men, killed Elatus who dwelt in Pedasus by the
+banks of the river Satnioeis. Leitus killed Phylacus as he was
+flying, and Eurypylus slew Melanthus.
+</para>
+
+<para>
+Then Menelaus of the loud war-cry took Adrestus alive, for his
+horses ran into a tamarisk bush, as they were flying wildly over
+the plain, and broke the pole from the car; they went on towards
+the city along with the others in full flight, but Adrestus
+rolled out, and fell in the dust flat on his face by the wheel of
+his chariot; Menelaus came up to him spear in hand, but Adrestus
+caught him by the knees begging for his life. "Take me alive," he
+cried, "son of Atreus, and you shall have a full ransom for me:
+my father is rich and has much treasure of gold, bronze, and
+wrought iron laid by in his house. From this store he will give
+you a large ransom should he hear of my being alive and at the
+ships of the Achaeans."
+</para>
+
+<para>
+Thus did he plead, and Menelaus was for yielding and giving him
+to a squire to take to the ships of the Achaeans, but Agamemnon
+came running up to him and rebuked him. "My good Menelaus," said
+he, "this is no time for giving quarter. Has, then, your house
+fared so well at the hands of the Trojans? Let us not spare a
+single one of them--not even the child unborn and in its mother's
+womb; let not a man of them be left alive, but let all in Ilius
+perish, unheeded and forgotten."
+</para>
+
+<para>
+Thus did he speak, and his brother was persuaded by him, for his
+words were just. Menelaus, therefore, thrust Adrestus from him,
+whereon King Agamemnon struck him in the flank, and he fell: then
+the son of Atreus planted his foot upon his breast to draw his
+spear from the body.
+</para>
+
+<para>
+Meanwhile Nestor shouted to the Argives, saying, "My friends,
+Danaan warriors, servants of Mars, let no man lag that he may
+spoil the dead, and bring back much booty to the ships. Let us
+kill as many as we can; the bodies will lie upon the plain, and
+you can despoil them later at your leisure."
+</para>
+
+<para>
+With these words he put heart and soul into them all. And now the
+Trojans would have been routed and driven back into Ilius, had
+not Priam's son Helenus, wisest of augurs, said to Hector and
+Aeneas, "Hector and Aeneas, you two are the mainstays of the
+Trojans and Lycians, for you are foremost at all times, alike in
+fight and counsel; hold your ground here, and go about among the
+host to rally them in front of the gates, or they will fling
+themselves into the arms of their wives, to the great joy of our
+foes. Then, when you have put heart into all our companies, we
+will stand firm here and fight the Danaans however hard they
+press us, for there is nothing else to be done. Meanwhile do you,
+Hector, go to the city and tell our mother what is happening.
+Tell her to bid the matrons gather at the temple of Minerva in
+the acropolis; let her then take her key and open the doors of
+the sacred building; there, upon the knees of Minerva, let her
+lay the largest, fairest robe she has in her house--the one she
+sets most store by; let her, moreover, promise to sacrifice
+twelve yearling heifers that have never yet felt the goad, in the
+temple of the goddess, if she will take pity on the town, with
+the wives and little ones of the Trojans, and keep the son of
+Tydeus from falling on the goodly city of Ilius; for he fights
+with fury and fills men's souls with panic. I hold him mightiest
+of them all; we did not fear even their great champion Achilles,
+son of a goddess though he be, as we do this man: his rage is
+beyond all bounds, and there is none can vie with him in prowess"
+</para>
+
+<para>
+Hector did as his brother bade him. He sprang from his chariot,
+and went about everywhere among the host, brandishing his spears,
+urging the men on to fight, and raising the dread cry of battle.
+Thereon they rallied and again faced the Achaeans, who gave
+ground and ceased their murderous onset, for they deemed that
+some one of the immortals had come down from starry heaven to
+help the Trojans, so strangely had they rallied. And Hector
+shouted to the Trojans, "Trojans and allies, be men, my friends,
+and fight with might and main, while I go to Ilius and tell the
+old men of our council and our wives to pray to the gods and vow
+hecatombs in their honour."
+</para>
+
+<para>
+With this he went his way, and the black rim of hide that went
+round his shield beat against his neck and his ancles.
+</para>
+
+<para>
+Then Glaucus son of Hippolochus, and the son of Tydeus went into
+the open space between the hosts to fight in single combat. When
+they were close up to one another Diomed of the loud war-cry was
+the first to speak. "Who, my good sir," said he, "who are you
+among men? I have never seen you in battle until now, but you are
+daring beyond all others if you abide my onset. Woe to those
+fathers whose sons face my might. If, however, you are one of the
+immortals and have come down from heaven, I will not fight you;
+for even valiant Lycurgus, son of Dryas, did not live long when
+he took to fighting with the gods. He it was that drove the
+nursing women who were in charge of frenzied Bacchus through the
+land of Nysa, and they flung their thyrsi on the ground as
+murderous Lycurgus beat them with his oxgoad. Bacchus himself
+plunged terror-stricken into the sea, and Thetis took him to her
+bosom to comfort him, for he was scared by the fury with which
+the man reviled him. Thereon the gods who live at ease were angry
+with Lycurgus and the son of Saturn struck him blind, nor did he
+live much longer after he had become hateful to the immortals.
+Therefore I will not fight with the blessed gods; but if you are
+of them that eat the fruit of the ground, draw near and meet your
+doom."
+</para>
+
+<para>
+And the son of Hippolochus answered, son of Tydeus, why ask me of
+my lineage? Men come and go as leaves year by year upon the
+trees. Those of autumn the wind sheds upon the ground, but when
+spring returns the forest buds forth with fresh vines. Even so is
+it with the generations of mankind, the new spring up as the old
+are passing away. If, then, you would learn my descent, it is one
+that is well known to many. There is a city in the heart of
+Argos, pasture land of horses, called Ephyra, where Sisyphus
+lived, who was the craftiest of all mankind. He was the son of
+Aeolus, and had a son named Glaucus, who was father to
+Bellerophon, whom heaven endowed with the most surpassing
+comeliness and beauty. But Proetus devised his ruin, and being
+stronger than he, drove him from the land of the Argives, over
+which Jove had made him ruler. For Antea, wife of Proetus, lusted
+after him, and would have had him lie with her in secret; but
+Bellerophon was an honourable man and would not, so she told lies
+about him to Proteus. 'Proetus,' said she, 'kill Bellerophon or
+die, for he would have had converse with me against my will.' The
+king was angered, but shrank from killing Bellerophon, so he sent
+him to Lycia with lying letters of introduction, written on a
+folded tablet, and containing much ill against the bearer. He
+bade Bellerophon show these letters to his father-in-law, to the
+end that he might thus perish; Bellerophon therefore went to
+Lycia, and the gods convoyed him safely.
+</para>
+
+<para>
+"When he reached the river Xanthus, which is in Lycia, the king
+received him with all goodwill, feasted him nine days, and killed
+nine heifers in his honour, but when rosy-fingered morning
+appeared upon the tenth day, he questioned him and desired to see
+the letter from his son-in-law Proetus. When he had received the
+wicked letter he first commanded Bellerophon to kill that savage
+monster, the Chimaera, who was not a human being, but a goddess,
+for she had the head of a lion and the tail of a serpent, while
+her body was that of a goat, and she breathed forth flames of
+fire; but Bellerophon slew her, for he was guided by signs from
+heaven. He next fought the far-famed Solymi, and this, he said,
+was the hardest of all his battles. Thirdly, he killed the
+Amazons, women who were the peers of men, and as he was returning
+thence the king devised yet another plan for his destruction; he
+picked the bravest warriors in all Lycia, and placed them in
+ambuscade, but not a man ever came back, for Bellerophon killed
+every one of them. Then the king knew that he must be the valiant
+offspring of a god, so he kept him in Lycia, gave him his
+daughter in marriage, and made him of equal honour in the kingdom
+with himself; and the Lycians gave him a piece of land, the best
+in all the country, fair with vineyards and tilled fields, to
+have and to hold.
+</para>
+
+<para>
+"The king's daughter bore Bellerophon three children, Isander,
+Hippolochus, and Laodameia. Jove, the lord of counsel, lay with
+Laodameia, and she bore him noble Sarpedon; but when Bellerophon
+came to be hated by all the gods, he wandered all desolate and
+dismayed upon the Alean plain, gnawing at his own heart, and
+shunning the path of man. Mars, insatiate of battle, killed his
+son Isander while he was fighting the Solymi; his daughter was
+killed by Diana of the golden reins, for she was angered with
+her; but Hippolochus was father to myself, and when he sent me to
+Troy he urged me again and again to fight ever among the foremost
+and outvie my peers, so as not to shame the blood of my fathers
+who were the noblest in Ephyra and in all Lycia. This, then, is
+the descent I claim."
+</para>
+
+<para>
+Thus did he speak, and the heart of Diomed was glad. He planted
+his spear in the ground, and spoke to him with friendly words.
+"Then," he said, "you are an old friend of my father's house.
+Great Oeneus once entertained Bellerophon for twenty days, and
+the two exchanged presents. Oeneus gave a belt rich with purple,
+and Bellerophon a double cup, which I left at home when I set out
+for Troy. I do not remember Tydeus, for he was taken from us
+while I was yet a child, when the army of the Achaeans was cut to
+pieces before Thebes. Henceforth, however, I must be your host in
+middle Argos, and you mine in Lycia, if I should ever go there;
+let us avoid one another's spears even during a general
+engagement; there are many noble Trojans and allies whom I can
+kill, if I overtake them and heaven delivers them into my hand;
+so again with yourself, there are many Achaeans whose lives you
+may take if you can; we two, then, will exchange armour, that all
+present may know of the old ties that subsist between us."
+</para>
+
+<para>
+With these words they sprang from their chariots, grasped one
+another's hands, and plighted friendship. But the son of Saturn
+made Glaucus take leave of his wits, for he exchanged golden
+armour for bronze, the worth of a hundred head of cattle for the
+worth of nine.
+</para>
+
+<para>
+Now when Hector reached the Scaean gates and the oak tree, the
+wives and daughters of the Trojans came running towards him to
+ask after their sons, brothers, kinsmen, and husbands: he told
+them to set about praying to the gods, and many were made
+sorrowful as they heard him.
+</para>
+
+<para>
+Presently he reached the splendid palace of King Priam, adorned
+with colonnades of hewn stone. In it there were fifty
+bedchambers--all of hewn stone--built near one another, where the
+sons of Priam slept, each with his wedded wife. Opposite these,
+on the other side the courtyard, there were twelve upper rooms
+also of hewn stone for Priam's daughters, built near one another,
+where his sons-in-law slept with their wives. When Hector got
+there, his fond mother came up to him with Laodice the fairest of
+her daughters. She took his hand within her own and said, "My
+son, why have you left the battle to come hither? Are the
+Achaeans, woe betide them, pressing you hard about the city that
+you have thought fit to come and uplift your hands to Jove from
+the citadel? Wait till I can bring you wine that you may make
+offering to Jove and to the other immortals, and may then drink
+and be refreshed. Wine gives a man fresh strength when he is
+wearied, as you now are with fighting on behalf of your kinsmen."
+</para>
+
+<para>
+And Hector answered, "Honoured mother, bring no wine, lest you
+unman me and I forget my strength. I dare not make a
+drink-offering to Jove with unwashed hands; one who is
+bespattered with blood and filth may not pray to the son of
+Saturn. Get the matrons together, and go with offerings to the
+temple of Minerva driver of the spoil; there, upon the knees of
+Minerva, lay the largest and fairest robe you have in your
+house--the one you set most store by; promise, moreover, to
+sacrifice twelve yearling heifers that have never yet felt the
+goad, in the temple of the goddess if she will take pity on the
+town, with the wives and little ones of the Trojans, and keep the
+son of Tydeus from off the goodly city of Ilius, for he fights
+with fury, and fills men's souls with panic. Go, then, to the
+temple of Minerva, while I seek Paris and exhort him, if he will
+hear my words. Would that the earth might open her jaws and
+swallow him, for Jove bred him to be the bane of the Trojans, and
+of Priam and Priam's sons. Could I but see him go down into the
+house of Hades, my heart would forget its heaviness."
+</para>
+
+<para>
+His mother went into the house and called her waiting-women who
+gathered the matrons throughout the city. She then went down into
+her fragrant store-room, where her embroidered robes were kept,
+the work of Sidonian women, whom Alexandrus had brought over from
+Sidon when he sailed the seas upon that voyage during which he
+carried off Helen. Hecuba took out the largest robe, and the one
+that was most beautifully enriched with embroidery, as an
+offering to Minerva: it glittered like a star, and lay at the
+very bottom of the chest. With this she went on her way and many
+matrons with her.
+</para>
+
+<para>
+When they reached the temple of Minerva, lovely Theano, daughter
+of Cisseus and wife of Antenor, opened the doors, for the Trojans
+had made her priestess of Minerva. The women lifted up their
+hands to the goddess with a loud cry, and Theano took the robe to
+lay it upon the knees of Minerva, praying the while to the
+daughter of great Jove. "Holy Minerva," she cried, "protectress
+of our city, mighty goddess, break the spear of Diomed and lay
+him low before the Scaean gates. Do this, and we will sacrifice
+twelve heifers that have never yet known the goad, in your
+temple, if you will have pity upon the town, with the wives and
+little ones of the Trojans." Thus she prayed, but Pallas Minerva
+granted not her prayer.
+</para>
+
+<para>
+While they were thus praying to the daughter of great Jove,
+Hector went to the fair house of Alexandrus, which he had built
+for him by the foremost builders in the land. They had built him
+his house, storehouse, and courtyard near those of Priam and
+Hector on the acropolis. Here Hector entered, with a spear eleven
+cubits long in his hand; the bronze point gleamed in front of
+him, and was fastened to the shaft of the spear by a ring of
+gold. He found Alexandrus within the house, busied about his
+armour, his shield and cuirass, and handling his curved bow;
+there, too, sat Argive Helen with her women, setting them their
+several tasks; and as Hector saw him he rebuked him with words of
+scorn. "Sir," said he, "you do ill to nurse this rancour; the
+people perish fighting round this our town; you would yourself
+chide one whom you saw shirking his part in the combat. Up then,
+or ere long the city will be in a blaze."
+</para>
+
+<para>
+And Alexandrus answered, "Hector, your rebuke is just; listen
+therefore, and believe me when I tell you that I am not here so
+much through rancour or ill-will towards the Trojans, as from a
+desire to indulge my grief. My wife was even now gently urging me
+to battle, and I hold it better that I should go, for victory is
+ever fickle. Wait, then, while I put on my armour, or go first
+and I will follow. I shall be sure to overtake you."
+</para>
+
+<para>
+Hector made no answer, but Helen tried to soothe him. "Brother,"
+said she, "to my abhorred and sinful self, would that a whirlwind
+had caught me up on the day my mother brought me forth, and had
+borne me to some mountain or to the waves of the roaring sea that
+should have swept me away ere this mischief had come about. But,
+since the gods have devised these evils, would, at any rate, that
+I had been wife to a better man--to one who could smart under
+dishonour and men's evil speeches. This fellow was never yet to
+be depended upon, nor never will be, and he will surely reap what
+he has sown. Still, brother, come in and rest upon this seat, for
+it is you who bear the brunt of that toil that has been caused by
+my hateful self and by the sin of Alexandrus--both of whom Jove
+has doomed to be a theme of song among those that shall be born
+hereafter."
+</para>
+
+<para>
+And Hector answered, "Bid me not be seated, Helen, for all the
+goodwill you bear me. I cannot stay. I am in haste to help the
+Trojans, who miss me greatly when I am not among them; but urge
+your husband, and of his own self also let him make haste to
+overtake me before I am out of the city. I must go home to see my
+household, my wife and my little son, for I know not whether I
+shall ever again return to them, or whether the gods will cause
+me to fill by the hands of the Achaeans."
+</para>
+
+<para>
+Then Hector left her, and forthwith was at his own house. He did
+not find Andromache, for she was on the wall with her child and
+one of her maids, weeping bitterly. Seeing, then, that she was
+not within, he stood on the threshold of the women's rooms and
+said, "Women, tell me, and tell me true, where did Andromache go
+when she left the house? Was it to my sisters, or to my brothers'
+wives? or is she at the temple of Minerva where the other women
+are propitiating the awful goddess?"
+</para>
+
+<para>
+His good housekeeper answered, "Hector, since you bid me tell you
+truly, she did not go to your sisters nor to your brothers'
+wives, nor yet to the temple of Minerva, where the other women
+are propitiating the awful goddess, but she is on the high wall
+of Ilius, for she had heard the Trojans were being hard pressed,
+and that the Achaeans were in great force: she went to the wall
+in frenzied haste, and the nurse went with her carrying the
+child."
+</para>
+
+<para>
+Hector hurried from the house when she had done speaking, and
+went down the streets by the same way that he had come. When he
+had gone through the city and had reached the Scaean gates
+through which he would go out on to the plain, his wife came
+running towards him, Andromache, daughter of great Eetion who
+ruled in Thebe under the wooded slopes of Mt. Placus, and was
+king of the Cilicians. His daughter had married Hector, and now
+came to meet him with a nurse who carried his little child in her
+bosom--a mere babe. Hector's darling son, and lovely as a star.
+Hector had named him Scamandrius, but the people called him
+Astyanax, for his father stood alone as chief guardian of Ilius.
+Hector smiled as he looked upon the boy, but he did not speak,
+and Andromache stood by him weeping and taking his hand in her
+own. "Dear husband," said she, "your valour will bring you to
+destruction; think on your infant son, and on my hapless self who
+ere long shall be your widow--for the Achaeans will set upon you
+in a body and kill you. It would be better for me, should I lose
+you, to lie dead and buried, for I shall have nothing left to
+comfort me when you are gone, save only sorrow. I have neither
+father nor mother now. Achilles slew my father when he sacked
+Thebe the goodly city of the Cilicians. He slew him, but did not
+for very shame despoil him; when he had burned him in his
+wondrous armour, he raised a barrow over his ashes and the
+mountain nymphs, daughters of aegis-bearing Jove, planted a grove
+of elms about his tomb. I had seven brothers in my father's
+house, but on the same day they all went within the house of
+Hades. Achilles killed them as they were with their sheep and
+cattle. My mother--her who had been queen of all the land under
+Mt. Placus--he brought hither with the spoil, and freed her for a
+great sum, but the archer-queen Diana took her in the house of
+your father. Nay--Hector--you who to me are father, mother,
+brother, and dear husband--have mercy upon me; stay here upon
+this wall; make not your child fatherless, and your wife a widow;
+as for the host, place them near the fig-tree, where the city can
+be best scaled, and the wall is weakest. Thrice have the bravest
+of them come thither and assailed it, under the two Ajaxes,
+Idomeneus, the sons of Atreus, and the brave son of Tydeus,
+either of their own bidding, or because some soothsayer had told
+them."
+</para>
+
+<para>
+And Hector answered, "Wife, I too have thought upon all this, but
+with what face should I look upon the Trojans, men or women, if I
+shirked battle like a coward? I cannot do so: I know nothing save
+to fight bravely in the forefront of the Trojan host and win
+renown alike for my father and myself. Well do I know that the
+day will surely come when mighty Ilius shall be destroyed with
+Priam and Priam's people, but I grieve for none of these--not
+even for Hecuba, nor King Priam, nor for my brothers many and
+brave who may fall in the dust before their foes--for none of
+these do I grieve as for yourself when the day shall come on
+which some one of the Achaeans shall rob you for ever of your
+freedom, and bear you weeping away. It may be that you will have
+to ply the loom in Argos at the bidding of a mistress, or to
+fetch water from the springs Messeis or Hypereia, treated
+brutally by some cruel task-master; then will one say who sees
+you weeping, 'She was wife to Hector, the bravest warrior among
+the Trojans during the war before Ilius.' On this your tears will
+break forth anew for him who would have put away the day of
+captivity from you. May I lie dead under the barrow that is
+heaped over my body ere I hear your cry as they carry you into
+bondage."
+</para>
+
+<para>
+He stretched his arms towards his child, but the boy cried and
+nestled in his nurse's bosom, scared at the sight of his father's
+armour, and at the horse-hair plume that nodded fiercely from his
+helmet. His father and mother laughed to see him, but Hector took
+the helmet from his head and laid it all gleaming upon the
+ground. Then he took his darling child, kissed him, and dandled
+him in his arms, praying over him the while to Jove and to all
+the gods. "Jove," he cried, "grant that this my child may be even
+as myself, chief among the Trojans; let him be not less excellent
+in strength, and let him rule Ilius with his might. Then may one
+say of him as he comes from battle, 'The son is far better than
+the father.' May he bring back the blood-stained spoils of him
+whom he has laid low, and let his mother's heart be glad.'"
+</para>
+
+<para>
+With this he laid the child again in the arms of his wife, who
+took him to her own soft bosom, smiling through her tears. As her
+husband watched her his heart yearned towards her and he caressed
+her fondly, saying, "My own wife, do not take these things too
+bitterly to heart. No one can hurry me down to Hades before my
+time, but if a man's hour is come, be he brave or be he coward,
+there is no escape for him when he has once been born. Go, then,
+within the house, and busy yourself with your daily duties, your
+loom, your distaff, and the ordering of your servants; for war is
+man's matter, and mine above all others of them that have been
+born in Ilius."
+</para>
+
+<para>
+He took his plumed helmet from the ground, and his wife went back
+again to her house, weeping bitterly and often looking back
+towards him. When she reached her home she found her maidens
+within, and bade them all join in her lament; so they mourned
+Hector in his own house though he was yet alive, for they deemed
+that they should never see him return safe from battle, and from
+the furious hands of the Achaeans.
+</para>
+
+<para>
+Paris did not remain long in his house. He donned his goodly
+armour overlaid with bronze, and hasted through the city as fast
+as his feet could take him. As a horse, stabled and fed, breaks
+loose and gallops gloriously over the plain to the place where he
+is wont to bathe in the fair-flowing river--he holds his head
+high, and his mane streams upon his shoulders as he exults in his
+strength and flies like the wind to the haunts and feeding ground
+of the mares--even so went forth Paris from high Pergamus,
+gleaming like sunlight in his armour, and he laughed aloud as he
+sped swiftly on his way. Forthwith he came upon his brother
+Hector, who was then turning away from the place where he had
+held converse with his wife, and he was himself the first to
+speak. "Sir," said he, "I fear that I have kept you waiting when
+you are in haste, and have not come as quickly as you bade me."
+</para>
+
+<para>
+"My good brother," answered Hector, "you fight bravely, and no
+man with any justice can make light of your doings in battle. But
+you are careless and wilfully remiss. It grieves me to the heart
+to hear the ill that the Trojans speak about you, for they have
+suffered much on your account. Let us be going, and we will make
+things right hereafter, should Jove vouchsafe us to set the cup
+of our deliverance before ever-living gods of heaven in our own
+homes, when we have chased the Achaeans from Troy."
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK VII</title>
+
+<para>
+WITH these words Hector passed through the gates, and his brother
+Alexandrus with him, both eager for the fray. As when heaven
+sends a breeze to sailors who have long looked for one in vain,
+and have laboured at their oars till they are faint with toil,
+even so welcome was the sight of these two heroes to the Trojans.
+</para>
+
+<para>
+Thereon Alexandrus killed Menesthius the son of Areithous; he
+lived in Arne, and was son of Areithous the Mace-man, and of
+Phylomedusa. Hector threw a spear at Eioneus and struck him dead
+with a wound in the neck under the bronze rim of his helmet.
+Glaucus, moreover, son of Hippolochus, captain of the Lycians, in
+hard hand-to-hand fight smote Iphinous son of Dexius on the
+shoulder, as he was springing on to his chariot behind his fleet
+mares; so he fell to earth from the car, and there was no life
+left in him.
+</para>
+
+<para>
+When, therefore, Minerva saw these men making havoc of the
+Argives, she darted down to Ilius from the summits of Olympus,
+and Apollo, who was looking on from Pergamus, went out to meet
+her; for he wanted the Trojans to be victorious. The pair met by
+the oak tree, and King Apollo son of Jove was first to speak.
+"What would you have", said he, "daughter of great Jove, that
+your proud spirit has sent you hither from Olympus? Have you no
+pity upon the Trojans, and would you incline the scales of
+victory in favour of the Danaans? Let me persuade you--for it
+will be better thus--stay the combat for to-day, but let them
+renew the fight hereafter till they compass the doom of Ilius,
+since you goddesses have made up your minds to destroy the city."
+</para>
+
+<para>
+And Minerva answered, "So be it, Far-Darter; it was in this mind
+that I came down from Olympus to the Trojans and Achaeans. Tell
+me, then, how do you propose to end this present fighting?"
+</para>
+
+<para>
+Apollo, son of Jove, replied, "Let us incite great Hector to
+challenge some one of the Danaans in single combat; on this the
+Achaeans will be shamed into finding a man who will fight him."
+</para>
+
+<para>
+Minerva assented, and Helenus son of Priam divined the counsel of
+the gods; he therefore went up to Hector and said, "Hector son of
+Priam, peer of gods in counsel, I am your brother, let me then
+persuade you. Bid the other Trojans and Achaeans all of them take
+their seats, and challenge the best man among the Achaeans to
+meet you in single combat. I have heard the voice of the
+ever-living gods, and the hour of your doom is not yet come."
+</para>
+
+<para>
+Hector was glad when he heard this saying, and went in among the
+Trojans, grasping his spear by the middle to hold them back, and
+they all sat down. Agamemnon also bade the Achaeans be seated.
+But Minerva and Apollo, in the likeness of vultures, perched on
+father Jove's high oak tree, proud of their men; and the ranks
+sat close ranged together, bristling with shield and helmet and
+spear. As when the rising west wind furs the face of the sea and
+the waters grow dark beneath it, so sat the companies of Trojans
+and Achaeans upon the plain. And Hector spoke thus:--
+</para>
+
+<para>
+"Hear me, Trojans and Achaeans, that I may speak even as I am
+minded; Jove on his high throne has brought our oaths and
+covenants to nothing, and foreshadows ill for both of us, till
+you either take the towers of Troy, or are yourselves vanquished
+at your ships. The princes of the Achaeans are here present in
+the midst of you; let him, then, that will fight me stand forward
+as your champion against Hector. Thus I say, and may Jove be
+witness between us. If your champion slay me, let him strip me of
+my armour and take it to your ships, but let him send my body
+home that the Trojans and their wives may give me my dues of fire
+when I am dead. In like manner, if Apollo vouchsafe me glory and
+I slay your champion, I will strip him of his armour and take it
+to the city of Ilius, where I will hang it in the temple of
+Apollo, but I will give up his body, that the Achaeans may bury
+him at their ships, and the build him a mound by the wide waters
+of the Hellespont. Then will one say hereafter as he sails his
+ship over the sea, 'This is the monument of one who died long
+since a champion who was slain by mighty Hector.' Thus will one
+say, and my fame shall not be lost."
+</para>
+
+<para>
+Thus did he speak, but they all held their peace, ashamed to
+decline the challenge, yet fearing to accept it, till at last
+Menelaus rose and rebuked them, for he was angry. "Alas," he
+cried, "vain braggarts, women forsooth not men, double-dyed
+indeed will be the stain upon us if no man of the Danaans will
+now face Hector. May you be turned every man of you into earth
+and water as you sit spiritless and inglorious in your places. I
+will myself go out against this man, but the upshot of the fight
+will be from on high in the hands of the immortal gods."
+</para>
+
+<para>
+With these words he put on his armour; and then, O Menelaus, your
+life would have come to an end at the hands of hands of Hector,
+for he was far better the man, had not the princes of the
+Achaeans sprung upon you and checked you. King Agamemnon caught
+him by the right hand and said, "Menelaus, you are mad; a truce
+to this folly. Be patient in spite of passion, do not think of
+fighting a man so much stronger than yourself as Hector son of
+Priam, who is feared by many another as well as you. Even
+Achilles, who is far more doughty than you are, shrank from
+meeting him in battle. Sit down your own people, and the Achaeans
+will send some other champion to fight Hector; fearless and fond
+of battle though he be, I ween his knees will bend gladly under
+him if he comes out alive from the hurly-burly of this fight."
+</para>
+
+<para>
+With these words of reasonable counsel he persuaded his brother,
+whereon his squires gladly stripped the armour from off his
+shoulders. Then Nestor rose and spoke, "Of a truth," said he,
+"the Achaean land is fallen upon evil times. The old knight
+Peleus, counsellor and orator among the Myrmidons, loved when I
+was in his house to question me concerning the race and lineage
+of all the Argives. How would it not grieve him could he hear of
+them as now quailing before Hector? Many a time would he lift his
+hands in prayer that his soul might leave his body and go down
+within the house of Hades. Would, by father Jove, Minerva, and
+Apollo, that I were still young and strong as when the Pylians
+and Arcadians were gathered in fight by the rapid river Celadon
+under the walls of Pheia, and round about the waters of the river
+Iardanus. The godlike hero Ereuthalion stood forward as their
+champion, with the armour of King Areithous upon his shoulders--
+Areithous whom men and women had surnamed 'the Mace-man,' because
+he fought neither with bow nor spear, but broke the battalions of
+the foe with his iron mace. Lycurgus killed him, not in fair
+fight, but by entrapping him in a narrow way where his mace
+served him in no stead; for Lycurgus was too quick for him and
+speared him through the middle, so he fell to earth on his back.
+Lycurgus then spoiled him of the armour which Mars had given him,
+and bore it in battle thenceforward; but when he grew old and
+stayed at home, he gave it to his faithful squire Ereuthalion,
+who in this same armour challenged the foremost men among us. The
+others quaked and quailed, but my high spirit bade me fight him
+though none other would venture; I was the youngest man of them
+all; but when I fought him Minerva vouchsafed me victory. He was
+the biggest and strongest man that ever I killed, and covered
+much ground as he lay sprawling upon the earth. Would that I were
+still young and strong as I then was, for the son of Priam would
+then soon find one who would face him. But you, foremost among
+the whole host though you be, have none of you any stomach for
+fighting Hector."
+</para>
+
+<para>
+Thus did the old man rebuke them, and forthwith nine men started
+to their feet. Foremost of all uprose King Agamemnon, and after
+him brave Diomed the son of Tydeus. Next were the two Ajaxes, men
+clothed in valour as with a garment, and then Idomeneus, and
+Meriones his brother in arms. After these Eurypylus son of
+Euaemon, Thoas the son of Andraemon, and Ulysses also rose. Then
+Nestor knight of Gerene again spoke, saying: "Cast lots among you
+to see who shall be chosen. If he come alive out of this fight he
+will have done good service alike to his own soul and to the
+Achaeans."
+</para>
+
+<para>
+Thus he spoke, and when each of them had marked his lot, and had
+thrown it into the helmet of Agamemnon son of Atreus, the people
+lifted their hands in prayer, and thus would one of them say as
+he looked into the vault of heaven, "Father Jove, grant that the
+lot fall on Ajax, or on the son of Tydeus, or upon the king of
+rich Mycene himself."
+</para>
+
+<para>
+As they were speaking, Nestor knight of Gerene shook the helmet,
+and from it there fell the very lot which they wanted--the lot of
+Ajax. The herald bore it about and showed it to all the
+chieftains of the Achaeans, going from left to right; but they
+none of them owned it. When, however, in due course he reached
+the man who had written upon it and had put it into the helmet,
+brave Ajax held out his hand, and the herald gave him the lot.
+When Ajax saw his mark he knew it and was glad; he threw it to
+the ground and said, "My friends, the lot is mine, and I rejoice,
+for I shall vanquish Hector. I will put on my armour; meanwhile,
+pray to King Jove in silence among yourselves that the Trojans
+may not hear you--or aloud if you will, for we fear no man. None
+shall overcome me, neither by force nor cunning, for I was born
+and bred in Salamis, and can hold my own in all things."
+</para>
+
+<para>
+With this they fell praying to King Jove the son of Saturn, and
+thus would one of them say as he looked into the vault of heaven,
+"Father Jove that rulest from Ida, most glorious in power,
+vouchsafe victory to Ajax, and let him win great glory: but if
+you wish well to Hector also and would protect him, grant to each
+of them equal fame and prowess."
+</para>
+
+<para>
+Thus they prayed, and Ajax armed himself in his suit of gleaming
+bronze. When he was in full array he sprang forward as monstrous
+Mars when he takes part among men whom Jove has set fighting with
+one another--even so did huge Ajax, bulwark of the Achaeans,
+spring forward with a grim smile on his face as he brandished his
+long spear and strode onward. The Argives were elated as they
+beheld him, but the Trojans trembled in every limb, and the heart
+even of Hector beat quickly, but he could not now retreat and
+withdraw into the ranks behind him, for he had been the
+challenger. Ajax came up bearing his shield in front of him like
+a wall--a shield of bronze with seven folds of oxhide--the work
+of Tychius, who lived in Hyle and was by far the best worker in
+leather. He had made it with the hides of seven full-fed bulls,
+and over these he had set an eighth layer of bronze. Holding this
+shield before him, Ajax son of Telamon came close up to Hector,
+and menaced him saying, "Hector, you shall now learn, man to man,
+what kind of champions the Danaans have among them even besides
+lion-hearted Achilles cleaver of the ranks of men. He now abides
+at the ships in anger with Agamemnon shepherd of his people, but
+there are many of us who are well able to face you; therefore
+begin the fight."
+</para>
+
+<para>
+And Hector answered, "Noble Ajax, son of Telamon, captain of the
+host, treat me not as though I were some puny boy or woman that
+cannot fight. I have been long used to the blood and butcheries
+of battle. I am quick to turn my leathern shield either to right
+or left, for this I deem the main thing in battle. I can charge
+among the chariots and horsemen, and in hand to hand fighting can
+delight the heart of Mars; howbeit I would not take such a man as
+you are off his guard--but I will smite you openly if I can."
+</para>
+
+<para>
+He poised his spear as he spoke, and hurled it from him. It
+struck the sevenfold shield in its outermost layer--the eighth,
+which was of bronze--and went through six of the layers but in
+the seventh hide it stayed. Then Ajax threw in his turn, and
+struck the round shield of the son of Priam. The terrible spear
+went through his gleaming shield, and pressed onward through his
+cuirass of cunning workmanship; it pierced the shirt against his
+side, but he swerved and thus saved his life. They then each of
+them drew out the spear from his shield, and fell on one another
+like savage lions or wild boars of great strength and endurance:
+the son of Priam struck the middle of Ajax's shield, but the
+bronze did not break, and the point of his dart was turned. Ajax
+then sprang forward and pierced the shield of Hector; the spear
+went through it and staggered him as he was springing forward to
+attack; it gashed his neck and the blood came pouring from the
+wound, but even so Hector did not cease fighting; he gave ground,
+and with his brawny hand seized a stone, rugged and huge, that
+was lying upon the plain; with this he struck the shield of Ajax
+on the boss that was in its middle, so that the bronze rang
+again. But Ajax in turn caught up a far larger stone, swung it
+aloft, and hurled it with prodigious force. This millstone of a
+rock broke Hector's shield inwards and threw him down on his back
+with the shield crushing him under it, but Apollo raised him at
+once. Thereon they would have hacked at one another in close
+combat with their swords, had not heralds, messengers of gods and
+men, come forward, one from the Trojans and the other from the
+Achaeans--Talthybius and Idaeus both of them honourable men;
+these parted them with their staves, and the good herald Idaeus
+said, "My sons, fight no longer, you are both of you valiant, and
+both are dear to Jove; we know this; but night is now falling,
+and the behests of night may not be well gainsaid."
+</para>
+
+<para>
+Ajax son of Telamon answered, "Idaeus, bid Hector say so, for it
+was he that challenged our princes. Let him speak first and I
+will accept his saying."
+</para>
+
+<para>
+Then Hector said, "Ajax, heaven has vouchsafed you stature and
+strength, and judgement; and in wielding the spear you excel all
+others of the Achaeans. Let us for this day cease fighting;
+hereafter we will fight anew till heaven decide between us, and
+give victory to one or to the other; night is now falling, and
+the behests of night may not be well gainsaid. Gladden, then, the
+hearts of the Achaeans at your ships, and more especially those
+of your own followers and clansmen, while I, in the great city of
+King Priam, bring comfort to the Trojans and their women, who vie
+with one another in their prayers on my behalf. Let us, moreover,
+exchange presents that it may be said among the Achaeans and
+Trojans, 'They fought with might and main, but were reconciled
+and parted in friendship.'"
+</para>
+
+<para>
+On this he gave Ajax a silver-studded sword with its sheath and
+leathern baldric, and in return Ajax gave him a girdle dyed with
+purple. Thus they parted, the one going to the host of the
+Achaeans, and the other to that of the Trojans, who rejoiced when
+they saw their hero come to them safe and unharmed from the
+strong hands of mighty Ajax. They led him, therefore, to the city
+as one that had been saved beyond their hopes. On the other side
+the Achaeans brought Ajax elated with victory to Agamemnon.
+</para>
+
+<para>
+When they reached the quarters of the son of Atreus, Agamemnon
+sacrificed for them a five-year-old bull in honour of Jove the
+son of Saturn. They flayed the carcass, made it ready, and
+divided it into joints; these they cut carefully up into smaller
+pieces, putting them on the spits, roasting them sufficiently,
+and then drawing them off. When they had done all this and had
+prepared the feast, they ate it, and every man had his full and
+equal share, so that all were satisfied, and King Agamemnon gave
+Ajax some slices cut lengthways down the loin, as a mark of
+special honour. As soon as they had had enough to eat and drink,
+old Nestor whose counsel was ever truest began to speak; with all
+sincerity and goodwill, therefore, he addressed them thus:--
+</para>
+
+<para>
+"Son of Atreus, and other chieftains, inasmuch as many of the
+Achaeans are now dead, whose blood Mars has shed by the banks of
+the Scamander, and their souls have gone down to the house of
+Hades, it will be well when morning comes that we should cease
+fighting; we will then wheel our dead together with oxen and
+mules and burn them not far from the ships, that when we sail
+hence we may take the bones of our comrades home to their
+children. Hard by the funeral pyre we will build a barrow that
+shall be raised from the plain for all in common; near this let
+us set about building a high wall, to shelter ourselves and our
+ships, and let it have well-made gates that there may be a way
+through them for our chariots. Close outside we will dig a deep
+trench all round it to keep off both horse and foot, that the
+Trojan chieftains may not bear hard upon us."
+</para>
+
+<para>
+Thus he spoke, and the princess shouted in applause. Meanwhile
+the Trojans held a council, angry and full of discord, on the
+acropolis by the gates of King Priam's palace; and wise Antenor
+spoke. "Hear me," he said, "Trojans, Dardanians, and allies, that
+I may speak even as I am minded. Let us give up Argive Helen and
+her wealth to the sons of Atreus, for we are now fighting in
+violation of our solemn covenants, and shall not prosper till we
+have done as I say."
+</para>
+
+<para>
+He then sat down and Alexandrus husband of lovely Helen rose to
+speak. "Antenor," said he, "your words are not to my liking; you
+can find a better saying than this if you will; if, however, you
+have spoken in good earnest, then indeed has heaven robbed you of
+your reason. I will speak plainly, and hereby notify to the
+Trojans that I will not give up the woman; but the wealth that I
+brought home with her from Argos I will restore, and will add yet
+further of my own."
+</para>
+
+<para>
+On this, when Paris had spoken and taken his seat, Priam of the
+race of Dardanus, peer of gods in council, rose and with all
+sincerity and goodwill addressed them thus: "Hear me, Trojans,
+Dardanians, and allies, that I may speak even as I am minded. Get
+your suppers now as hitherto throughout the city, but keep your
+watches and be wakeful. At daybreak let Idaeus go to the ships,
+and tell Agamemnon and Menelaus sons of Atreus the saying of
+Alexandrus through whom this quarrel has come about; and let him
+also be instant with them that they now cease fighting till we
+burn our dead; hereafter we will fight anew, till heaven decide
+between us and give victory to one or to the other."
+</para>
+
+<para>
+Thus did he speak, and they did even as he had said. They took
+supper in their companies and at daybreak Idaeus went his way to
+the ships. He found the Danaans, servants of Mars, in council at
+the stern of Agamemnon's ship, and took his place in the midst of
+them. "Son of Atreus," he said, "and princes of the Achaean host,
+Priam and the other noble Trojans have sent me to tell you the
+saying of Alexandrus through whom this quarrel has come about, if
+so be that you may find it acceptable. All the treasure he took
+with him in his ships to Troy--would that he had sooner
+perished--he will restore, and will add yet further of his own,
+but he will not give up the wedded wife of Menelaus, though the
+Trojans would have him do so. Priam bade me inquire further if
+you will cease fighting till we burn our dead; hereafter we will
+fight anew, till heaven decide between us and give victory to one
+or to the other."
+</para>
+
+<para>
+They all held their peace, but presently Diomed of the loud
+war-cry spoke, saying, "Let there be no taking, neither treasure,
+nor yet Helen, for even a child may see that the doom of the
+Trojans is at hand."
+</para>
+
+<para>
+The sons of the Achaeans shouted applause at the words that
+Diomed had spoken, and thereon King Agamemnon said to Idaeus,
+"Idaeus, you have heard the answer the Achaeans make you-and I
+with them. But as concerning the dead, I give you leave to burn
+them, for when men are once dead there should be no grudging them
+the rites of fire. Let Jove the mighty husband of Juno be witness
+to this covenant."
+</para>
+
+<para>
+As he spoke he upheld his sceptre in the sight of all the gods,
+and Idaeus went back to the strong city of Ilius. The Trojans and
+Dardanians were gathered in council waiting his return; when he
+came, he stood in their midst and delivered his message. As soon
+as they heard it they set about their twofold labour, some to
+gather the corpses, and others to bring in wood. The Argives on
+their part also hastened from their ships, some to gather the
+corpses, and others to bring in wood.
+</para>
+
+<para>
+The sun was beginning to beat upon the fields, fresh risen into
+the vault of heaven from the slow still currents of deep Oceanus,
+when the two armies met. They could hardly recognise their dead,
+but they washed the clotted gore from off them, shed tears over
+them, and lifted them upon their waggons. Priam had forbidden the
+Trojans to wail aloud, so they heaped their dead sadly and
+silently upon the pyre, and having burned them went back to the
+city of Ilius. The Achaeans in like manner heaped their dead
+sadly and silently on the pyre, and having burned them went back
+to their ships.
+</para>
+
+<para>
+Now in the twilight when it was not yet dawn, chosen bands of the
+Achaeans were gathered round the pyre and built one barrow that
+was raised in common for all, and hard by this they built a high
+wall to shelter themselves and their ships; they gave it strong
+gates that there might be a way through them for their chariots,
+and close outside it they dug a trench deep and wide, and they
+planted it within with stakes.
+</para>
+
+<para>
+Thus did the Achaeans toil, and the gods, seated by the side of
+Jove the lord of lightning, marvelled at their great work; but
+Neptune, lord of the earthquake, spoke, saying, "Father Jove,
+what mortal in the whole world will again take the gods into his
+counsel? See you not how the Achaeans have built a wall about
+their ships and driven a trench all round it, without offering
+hecatombs to the gods? The fame of this wall will reach as far as
+dawn itself, and men will no longer think anything of the one
+which Phoebus Apollo and myself built with so much labour for
+Laomedon."
+</para>
+
+<para>
+Jove was displeased and answered, "What, O shaker of the earth,
+are you talking about? A god less powerful than yourself might be
+alarmed at what they are doing, but your fame reaches as far as
+dawn itself. Surely when the Achaeans have gone home with their
+ships, you can shatter their wall and fling it into the sea; you
+can cover the beach with sand again, and the great wall of the
+Achaeans will then be utterly effaced."
+</para>
+
+<para>
+Thus did they converse, and by sunset the work of the Achaeans
+was completed; they then slaughtered oxen at their tents and got
+their supper. Many ships had come with wine from Lemnos, sent by
+Euneus the son of Jason, born to him by Hypsipyle. The son of
+Jason freighted them with ten thousand measures of wine, which he
+sent specially to the sons of Atreus, Agamemnon and Menelaus.
+From this supply the Achaeans bought their wine, some with
+bronze, some with iron, some with hides, some with whole heifers,
+and some again with captives. They spread a goodly banquet and
+feasted the whole night through, as also did the Trojans and
+their allies in the city. But all the time Jove boded them ill
+and roared with his portentous thunder. Pale fear got hold upon
+them, and they spilled the wine from their cups on to the ground,
+nor did any dare drink till he had made offerings to the most
+mighty son of Saturn. Then they laid themselves down to rest and
+enjoyed the boon of sleep.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK VIII</title>
+
+<para>
+NOW when Morning, clad in her robe of saffron, had begun to
+suffuse light over the earth, Jove called the gods in council on
+the topmost crest of serrated Olympus. Then he spoke and all the
+other gods gave ear. "Hear me," said he, "gods and goddesses,
+that I may speak even as I am minded. Let none of you neither
+goddess nor god try to cross me, but obey me every one of you
+that I may bring this matter to an end. If I see anyone acting
+apart and helping either Trojans or Danaans, he shall be beaten
+inordinately ere he come back again to Olympus; or I will hurl
+him down into dark Tartarus far into the deepest pit under the
+earth, where the gates are iron and the floor bronze, as far
+beneath Hades as heaven is high above the earth, that you may
+learn how much the mightiest I am among you. Try me and find out
+for yourselves. Hangs me a golden chain from heaven, and lay hold
+of it all of you, gods and goddesses together--tug as you will,
+you will not drag Jove the supreme counsellor from heaven to
+earth; but were I to pull at it myself I should draw you up with
+earth and sea into the bargain, then would I bind the chain about
+some pinnacle of Olympus and leave you all dangling in the mid
+firmament. So far am I above all others either of gods or men."
+</para>
+
+<para>
+They were frightened and all of them of held their peace, for he
+had spoken masterfully; but at last Minerva answered, "Father,
+son of Saturn, king of kings, we all know that your might is not
+to be gainsaid, but we are also sorry for the Danaan warriors,
+who are perishing and coming to a bad end. We will, however,
+since you so bid us, refrain from actual fighting, but we will
+make serviceable suggestions to the Argives that they may not all
+of them perish in your displeasure."
+</para>
+
+<para>
+Jove smiled at her and answered, "Take heart, my child,
+Trito-born; I am not really in earnest, and I wish to be kind to
+you."
+</para>
+
+<para>
+With this he yoked his fleet horses, with hoofs of bronze and
+manes of glittering gold. He girded himself also with gold about
+the body, seized his gold whip and took his seat in his chariot.
+Thereon he lashed his horses and they flew forward nothing loth
+midway twixt earth and starry heaven. After a while he reached
+many-fountained Ida, mother of wild beasts, and Gargarus, where
+are his grove and fragrant altar. There the father of gods and
+men stayed his horses, took them from the chariot, and hid them
+in a thick cloud; then he took his seat all glorious upon the
+topmost crests, looking down upon the city of Troy and the ships
+of the Achaeans.
+</para>
+
+<para>
+The Achaeans took their morning meal hastily at the ships, and
+afterwards put on their armour. The Trojans on the other hand
+likewise armed themselves throughout the city, fewer in numbers
+but nevertheless eager perforce to do battle for their wives and
+children. All the gates were flung wide open, and horse and foot
+sallied forth with the tramp as of a great multitude.
+</para>
+
+<para>
+When they were got together in one place, shield clashed with
+shield, and spear with spear, in the conflict of mail-clad men.
+Mighty was the din as the bossed shields pressed hard on one
+another--death--cry and shout of triumph of slain and slayers,
+and the earth ran red with blood.
+</para>
+
+<para>
+Now so long as the day waxed and it was still morning their
+weapons beat against one another, and the people fell, but when
+the sun had reached mid-heaven, the sire of all balanced his
+golden scales, and put two fates of death within them, one for
+the Trojans and the other for the Achaeans. He took the balance
+by the middle, and when he lifted it up the day of the Achaeans
+sank; the death-fraught scale of the Achaeans settled down upon
+the ground, while that of the Trojans rose heavenwards. Then he
+thundered aloud from Ida, and sent the glare of his lightning
+upon the Achaeans; when they saw this, pale fear fell upon them
+and they were sore afraid.
+</para>
+
+<para>
+Idomeneus dared not stay nor yet Agamemnon, nor did the two
+Ajaxes, servants of Mars, hold their ground. Nestor knight of
+Gerene alone stood firm, bulwark of the Achaeans, not of his own
+will, but one of his horses was disabled. Alexandrus husband of
+lovely Helen had hit it with an arrow just on the top of its head
+where the mane begins to grow away from the skull, a very deadly
+place. The horse bounded in his anguish as the arrow pierced his
+brain, and his struggles threw others into confusion. The old man
+instantly began cutting the traces with his sword, but Hector's
+fleet horses bore down upon him through the rout with their bold
+charioteer, even Hector himself, and the old man would have
+perished there and then had not Diomed been quick to mark, and
+with a loud cry called Ulysses to help him.
+</para>
+
+<para>
+"Ulysses," he cried, "noble son of Laertes where are you flying
+to, with your back turned like a coward? See that you are not
+struck with a spear between the shoulders. Stay here and help me
+to defend Nestor from this man's furious onset."
+</para>
+
+<para>
+Ulysses would not give ear, but sped onward to the ships of the
+Achaeans, and the son of Tydeus flinging himself alone into the
+thick of the fight took his stand before the horses of the son of
+Neleus. "Sir," said he, "these young warriors are pressing you
+hard, your force is spent, and age is heavy upon you, your squire
+is naught, and your horses are slow to move. Mount my chariot and
+see what the horses of Tros can do--how cleverly they can scud
+hither and thither over the plain either in flight or in pursuit.
+I took them from the hero Aeneas. Let our squires attend to your
+own steeds, but let us drive mine straight at the Trojans, that
+Hector may learn how furiously I too can wield my spear."
+</para>
+
+<para>
+Nestor knight of Gerene hearkened to his words. Thereon the
+doughty squires, Sthenelus and kind-hearted Eurymedon, saw to
+Nestor's horses, while the two both mounted Diomed's chariot.
+Nestor took the reins in his hands and lashed the horses on; they
+were soon close up with Hector, and the son of Tydeus aimed a
+spear at him as he was charging full speed towards them. He
+missed him, but struck his charioteer and squire Eniopeus son of
+noble Thebaeus in the breast by the nipple while the reins were
+in his hands, so that he died there and then, and the horses
+swerved as he fell headlong from the chariot. Hector was greatly
+grieved at the loss of his charioteer, but let him lie for all
+his sorrow, while he went in quest of another driver; nor did his
+steeds have to go long without one, for he presently found brave
+Archeptolemus the son of Iphitus, and made him get up behind the
+horses, giving the reins into his hand.
+</para>
+
+<para>
+All had then been lost and no help for it, for they would have
+been penned up in Ilius like sheep, had not the sire of gods and
+men been quick to mark, and hurled a fiery flaming thunderbolt
+which fell just in front of Diomed's horses with a flare of
+burning brimstone. The horses were frightened and tried to back
+beneath the car, while the reins dropped from Nestor's hands.
+Then he was afraid and said to Diomed, "Son of Tydeus, turn your
+horses in flight; see you not that the hand of Jove is against
+you? To-day he vouchsafes victory to Hector; to-morrow, if it so
+please him, he will again grant it to ourselves; no man, however
+brave, may thwart the purpose of Jove, for he is far stronger
+than any."
+</para>
+
+<para>
+Diomed answered, "All that you have said is true; there is a
+grief however which pierces me to the very heart, for Hector will
+talk among the Trojans and say, 'The son of Tydeus fled before me
+to the ships.' This is the vaunt he will make, and may earth then
+swallow me."
+</para>
+
+<para>
+"Son of Tydeus," replied Nestor, "what mean you? Though Hector
+say that you are a coward the Trojans and Dardanians will not
+believe him, nor yet the wives of the mighty warriors whom you
+have laid low."
+</para>
+
+<para>
+So saying he turned the horses back through the thick of the
+battle, and with a cry that rent the air the Trojans and Hector
+rained their darts after them. Hector shouted to him and said,
+"Son of Tydeus, the Danaans have done you honour hitherto as
+regards your place at table, the meals they give you, and the
+filling of your cup with wine. Henceforth they will despise you,
+for you are become no better than a woman. Be off, girl and
+coward that you are, you shall not scale our walls through any
+flinching upon my part; neither shall you carry off our wives in
+your ships, for I shall kill you with my own hand."
+</para>
+
+<para>
+The son of Tydeus was in two minds whether or no to turn his
+horses round again and fight him. Thrice did he doubt, and thrice
+did Jove thunder from the heights of Ida in token to the Trojans
+that he would turn the battle in their favour. Hector then
+shouted to them and said, "Trojans, Lycians, and Dardanians,
+lovers of close fighting, be men, my friends, and fight with
+might and with main; I see that Jove is minded to vouchsafe
+victory and great glory to myself, while he will deal destruction
+upon the Danaans. Fools, for having thought of building this weak
+and worthless wall. It shall not stay my fury; my horses will
+spring lightly over their trench, and when I am at their ships
+forget not to bring me fire that I may burn them, while I
+slaughter the Argives who will be all dazed and bewildered by the
+smoke."
+</para>
+
+<para>
+Then he cried to his horses, "Xanthus and Podargus, and you
+Aethon and goodly Lampus, pay me for your keep now and for all
+the honey-sweet corn with which Andromache daughter of great
+Eetion has fed you, and for she has mixed wine and water for you
+to drink whenever you would, before doing so even for me who am
+her own husband. Haste in pursuit, that we may take the shield of
+Nestor, the fame of which ascends to heaven, for it is of solid
+gold, arm-rods and all, and that we may strip from the shoulders
+of Diomed. the cuirass which Vulcan made him. Could we take these
+two things, the Achaeans would set sail in their ships this
+self-same night."
+</para>
+
+<para>
+Thus did he vaunt, but Queen Juno made high Olympus quake as she
+shook with rage upon her throne. Then said she to the mighty god
+of Neptune, "What now, wide ruling lord of the earthquake? Can
+you find no compassion in your heart for the dying Danaans, who
+bring you many a welcome offering to Helice and to Aegae? Wish
+them well then. If all of us who are with the Danaans were to
+drive the Trojans back and keep Jove from helping them, he would
+have to sit there sulking alone on Ida."
+</para>
+
+<para>
+King Neptune was greatly troubled and answered, "Juno, rash of
+tongue, what are you talking about? We other gods must not set
+ourselves against Jove, for he is far stronger than we are."
+</para>
+
+<para>
+Thus did they converse; but the whole space enclosed by the
+ditch, from the ships even to the wall, was filled with horses
+and warriors, who were pent up there by Hector son of Priam, now
+that the hand of Jove was with him. He would even have set fire
+to the ships and burned them, had not Queen Juno put it into the
+mind of Agamemnon, to bestir himself and to encourage the
+Achaeans. To this end he went round the ships and tents carrying
+a great purple cloak, and took his stand by the huge black hull
+of Ulysses' ship, which was middlemost of all; it was from this
+place that his voice would carry farthest, on the one hand
+towards the tents of Ajax son of Telamon, and on the other
+towards those of Achilles--for these two heroes, well assured of
+their own strength, had valorously drawn up their ships at the
+two ends of the line. From this spot then, with a voice that
+could be heard afar, he shouted to the Danaans, saying, "Argives,
+shame on you cowardly creatures, brave in semblance only; where
+are now our vaunts that we should prove victorious--the vaunts we
+made so vaingloriously in Lemnos, when we ate the flesh of horned
+cattle and filled our mixing-bowls to the brim? You vowed that
+you would each of you stand against a hundred or two hundred men,
+and now you prove no match even for one--for Hector, who will be
+ere long setting our ships in a blaze. Father Jove, did you ever
+so ruin a great king and rob him so utterly of his greatness?
+Yet, when to my sorrow I was coming hither, I never let my ship
+pass your altars without offering the fat and thigh-bones of
+heifers upon every one of them, so eager was I to sack the city
+of Troy. Vouchsafe me then this prayer--suffer us to escape at
+any rate with our lives, and let not the Achaeans be so utterly
+vanquished by the Trojans."
+</para>
+
+<para>
+Thus did he pray, and father Jove pitying his tears vouchsafed
+him that his people should live, not die; forthwith he sent them
+an eagle, most unfailingly portentous of all birds, with a young
+fawn in its talons; the eagle dropped the fawn by the altar on
+which the Achaeans sacrificed to Jove the lord of omens; when,
+therefore, the people saw that the bird had come from Jove, they
+sprang more fiercely upon the Trojans and fought more boldly.
+</para>
+
+<para>
+There was no man of all the many Danaans who could then boast
+that he had driven his horses over the trench and gone forth to
+fight sooner than the son of Tydeus; long before any one else
+could do so he slew an armed warrior of the Trojans, Agelaus the
+son of Phradmon. He had turned his horses in flight, but the
+spear struck him in the back midway between his shoulders and
+went right through his chest, and his armour rang rattling round
+him as he fell forward from his chariot.
+</para>
+
+<para>
+After him came Agamemnon and Menelaus, sons of Atreus, the two
+Ajaxes clothed in valour as with a garment, Idomeneus and his
+companion in arms Meriones, peer of murderous Mars, and Eurypylus
+the brave son of Euaemon. Ninth came Teucer with his bow, and
+took his place under cover of the shield of Ajax son of Telamon.
+When Ajax lifted his shield Teucer would peer round, and when he
+had hit any one in the throng, the man would fall dead; then
+Teucer would hie back to Ajax as a child to its mother, and again
+duck down under his shield.
+</para>
+
+<para>
+Which of the Trojans did brave Teucer first kill? Orsilochus, and
+then Ormenus and Ophelestes, Daetor, Chromius, and godlike
+Lycophontes, Amopaon son of Polyaemon, and Melanippus. these in
+turn did he lay low upon the earth, and King Agamemnon was glad
+when he saw him making havoc of the Trojans with his mighty bow.
+He went up to him and said, "Teucer, man after my own heart, son
+of Telamon, captain among the host, shoot on, and be at once the
+saving of the Danaans and the glory of your father Telamon, who
+brought you up and took care of you in his own house when you
+were a child, bastard though you were. Cover him with glory
+though he is far off; I will promise and I will assuredly
+perform; if aegis-bearing Jove and Minerva grant me to sack the
+city of Ilius, you shall have the next best meed of honour after
+my own--a tripod, or two horses with their chariot, or a woman
+who shall go up into your bed."
+</para>
+
+<para>
+And Teucer answered, "Most noble son of Atreus, you need not urge
+me; from the moment we began to drive them back to Ilius, I have
+never ceased so far as in me lies to look out for men whom I can
+shoot and kill; I have shot eight barbed shafts, and all of them
+have been buried in the flesh of warlike youths, but this mad dog
+I cannot hit."
+</para>
+
+<para>
+As he spoke he aimed another arrow straight at Hector, for he was
+bent on hitting him; nevertheless he missed him, and the arrow
+hit Priam's brave son Gorgythion in the breast. His mother, fair
+Castianeira, lovely as a goddess, had been married from Aesyme,
+and now he bowed his head as a garden poppy in full bloom when it
+is weighed down by showers in spring--even thus heavy bowed his
+head beneath the weight of his helmet.
+</para>
+
+<para>
+Again he aimed at Hector, for he was longing to hit him, and
+again his arrow missed, for Apollo turned it aside; but he hit
+Hector's brave charioteer Archeptolemus in the breast, by the
+nipple, as he was driving furiously into the fight. The horses
+swerved aside as he fell headlong from the chariot, and there was
+no life left in him. Hector was greatly grieved at the loss of
+his charioteer, but for all his sorrow he let him lie where he
+fell, and bade his brother Cebriones, who was hard by, take the
+reins. Cebriones did as he had said. Hector thereon with a loud
+cry sprang from his chariot to the ground, and seizing a great
+stone made straight for Teucer with intent kill him. Teucer had
+just taken an arrow from his quiver and had laid it upon the
+bow-string, but Hector struck him with the jagged stone as he was
+taking aim and drawing the string to his shoulder; he hit him
+just where the collar-bone divides the neck from the chest, a
+very deadly place, and broke the sinew of his arm so that his
+wrist was less, and the bow dropped from his hand as he fell
+forward on his knees. Ajax saw that his brother had fallen, and
+running towards him bestrode him and sheltered him with his
+shield. Meanwhile his two trusty squires, Mecisteus son of
+Echius, and Alastor, came up and bore him to the ships groaning
+in his great pain.
+</para>
+
+<para>
+Jove now again put heart into the Trojans, and they drove the
+Achaeans to their deep trench with Hector in all his glory at
+their head. As a hound grips a wild boar or lion in flank or
+buttock when he gives him chase, and watches warily for his
+wheeling, even so did Hector follow close upon the Achaeans, ever
+killing the hindmost as they rushed panic-stricken onwards. When
+they had fled through the set stakes and trench and many Achaeans
+had been laid low at the hands of the Trojans, they halted at
+their ships, calling upon one another and praying every man
+instantly as they lifted up their hands to the gods; but Hector
+wheeled his horses this way and that, his eyes glaring like those
+of Gorgo or murderous Mars.
+</para>
+
+<para>
+Juno when she saw them had pity upon them, and at once said to
+Minerva, "Alas, child of aegis-bearing Jove, shall you and I take
+no more thought for the dying Danaans, though it be the last time
+we ever do so? See how they perish and come to a bad end before
+the onset of but a single man. Hector the son of Priam rages with
+intolerable fury, and has already done great mischief."
+</para>
+
+<para>
+Minerva answered, "Would, indeed, this fellow might die in his
+own land, and fall by the hands of the Achaeans; but my father
+Jove is mad with spleen, ever foiling me, ever headstrong and
+unjust. He forgets how often I saved his son when he was worn out
+by the labours Eurystheus had laid on him. He would weep till his
+cry came up to heaven, and then Jove would send me down to help
+him; if I had had the sense to foresee all this, when Eurystheus
+sent him to the house of Hades, to fetch the hell-hound from
+Erebus, he would never have come back alive out of the deep
+waters of the river Styx. And now Jove hates me, while he lets
+Thetis have her way because she kissed his knees and took hold of
+his beard, when she was begging him to do honour to Achilles. I
+shall know what to do next time he begins calling me his
+grey-eyed darling. Get our horses ready, while I go within the
+house of aegis-bearing Jove and put on my armour; we shall then
+find out whether Priam's son Hector will be glad to meet us in
+the highways of battle, or whether the Trojans will glut hounds
+and vultures with the fat of their flesh as they be dead by the
+ships of the Achaeans."
+</para>
+
+<para>
+Thus did she speak and white-armed Juno, daughter of great
+Saturn, obeyed her words; she set about harnessing her
+gold-bedizened steeds, while Minerva daughter of aegis-bearing
+Jove flung her richly vesture, made with her own hands, on to the
+threshold of her father, and donned the shirt of Jove, arming
+herself for battle. Then she stepped into her flaming chariot,
+and grasped the spear so stout and sturdy and strong with which
+she quells the ranks of heroes who have displeased her. Juno
+lashed her horses, and the gates of heaven bellowed as they flew
+open of their own accord--gates over which the Hours preside, in
+whose hands are heaven and Olympus, either to open the dense
+cloud that hides them or to close it. Through these the goddesses
+drove their obedient steeds.
+</para>
+
+<para>
+But father Jove when he saw them from Ida was very angry, and
+sent winged Iris with a message to them. "Go," said he, "fleet
+Iris, turn them back, and see that they do not come near me, for
+if we come to fighting there will be mischief. This is what I
+say, and this is what I mean to do. I will lame their horses for
+them; I will hurl them from their chariot, and will break it in
+pieces. It will take them all ten years to heal the wounds my
+lightning shall inflict upon them; my grey-eyed daughter will
+then learn what quarrelling with her father means. I am less
+surprised and angry with Juno, for whatever I say she always
+contradicts me."
+</para>
+
+<para>
+With this Iris went her way, fleet as the wind, from the heights
+of Ida to the lofty summits of Olympus. She met the goddesses at
+the outer gates of its many valleys and gave them her message.
+"What," said she, "are you about? Are you mad? The son of Saturn
+forbids going. This is what he says, and this is he means to do,
+he will lame your horses for you, he will hurl you from your
+chariot, and will break it in pieces. It will take you all ten
+years to heal the wounds his lightning will inflict upon you,
+that you may learn, grey-eyed goddess, what quarrelling with your
+father means. He is less hurt and angry with Juno, for whatever
+he says she always contradicts him but you, bold hussy, will you
+really dare to raise your huge spear in defiance of Jove?"
+</para>
+
+<para>
+With this she left them, and Juno said to Minerva, "Of a truth,
+child of aegis-bearing Jove, I am not for fighting men's battles
+further in defiance of Jove. Let them live or die as luck will
+have it, and let Jove mete out his judgements upon the Trojans
+and Danaans according to his own pleasure."
+</para>
+
+<para>
+She turned her steeds; the Hours presently unyoked them, made
+them fast to their ambrosial mangers, and leaned the chariot
+against the end wall of the courtyard. The two goddesses then sat
+down upon their golden thrones, amid the company of the other
+gods; but they were very angry.
+</para>
+
+<para>
+Presently father Jove drove his chariot to Olympus, and entered
+the assembly of gods. The mighty lord of the earthquake unyoked
+his horses for him, set the car upon its stand, and threw a cloth
+over it. Jove then sat down upon his golden throne and Olympus
+reeled beneath him. Minerva and Juno sat alone, apart from Jove,
+and neither spoke nor asked him questions, but Jove knew what
+they meant, and said, "Minerva and Juno, why are you so angry?
+Are you fatigued with killing so many of your dear friends the
+Trojans? Be this as it may, such is the might of my hands that
+all the gods in Olympus cannot turn me; you were both of you
+trembling all over ere ever you saw the fight and its terrible
+doings. I tell you therefore-and it would have surely been--I
+should have struck you with lighting, and your chariots would
+never have brought you back again to Olympus."
+</para>
+
+<para>
+Minerva and Juno groaned in spirit as they sat side by side and
+brooded mischief for the Trojans. Minerva sat silent without a
+word, for she was in a furious passion and bitterly incensed
+against her father; but Juno could not contain herself and said,
+"What, dread son of Saturn, are you talking about? We know how
+great your power is, nevertheless we have compassion upon the
+Danaan warriors who are perishing and coming to a bad end. We
+will, however, since you so bid us, refrain from actual fighting,
+but we will make serviceable suggestions to the Argives, that
+they may not all of them perish in your displeasure."
+</para>
+
+<para>
+And Jove answered, "To-morrow morning, Juno, if you choose to do
+so, you will see the son of Saturn destroying large numbers of
+the Argives, for fierce Hector shall not cease fighting till he
+has roused the son of Peleus when they are fighting in dire
+straits at their ships' sterns about the body of Patroclus. Like
+it or no, this is how it is decreed; for aught I care, you may go
+to the lowest depths beneath earth and sea, where Iapetus and
+Saturn dwell in lone Tartarus with neither ray of light nor
+breath of wind to cheer them. You may go on and on till you get
+there, and I shall not care one whit for your displeasure; you
+are the greatest vixen living."
+</para>
+
+<para>
+Juno made him no answer. The sun's glorious orb now sank into
+Oceanus and drew down night over the land. Sorry indeed were the
+Trojans when light failed them, but welcome and thrice prayed for
+did darkness fall upon the Achaeans.
+</para>
+
+<para>
+Then Hector led the Trojans back from the ships, and held a
+council on the open space near the river, where there was a spot
+clear of corpses. They left their chariots and sat down on the
+ground to hear the speech he made them. He grasped a spear eleven
+cubits long, the bronze point of which gleamed in front of it,
+while the ring round the spear-head was of gold. Spear in hand he
+spoke. "Hear me," said he, "Trojans, Dardanians, and allies. I
+deemed but now that I should destroy the ships and all the
+Achaeans with them ere I went back to Ilius, but darkness came on
+too soon. It was this alone that saved them and their ships upon
+the seashore. Now, therefore, let us obey the behests of night,
+and prepare our suppers. Take your horses out of their chariots
+and give them their feeds of corn; then make speed to bring sheep
+and cattle from the city; bring wine also and corn for your
+horses and gather much wood, that from dark till dawn we may burn
+watchfires whose flare may reach to heaven. For the Achaeans may
+try to fly beyond the sea by night, and they must not embark
+scatheless and unmolested; many a man among them must take a dart
+with him to nurse at home, hit with spear or arrow as he is
+leaping on board his ship, that others may fear to bring war and
+weeping upon the Trojans. Moreover let the heralds tell it about
+the city that the growing youths and grey-bearded men are to camp
+upon its heaven-built walls. Let the women each of them light a
+great fire in her house, and let watch be safely kept lest the
+town be entered by surprise while the host is outside. See to it,
+brave Trojans, as I have said, and let this suffice for the
+moment; at daybreak I will instruct you further. I pray in hope
+to Jove and to the gods that we may then drive those fate-sped
+hounds from our land, for 'tis the fates that have borne them and
+their ships hither. This night, therefore, let us keep watch, but
+with early morning let us put on our armour and rouse fierce war
+at the ships of the Achaeans; I shall then know whether brave
+Diomed the son of Tydeus will drive me back from the ships to the
+wall, or whether I shall myself slay him and carry off his
+bloodstained spoils. To-morrow let him show his mettle, abide my
+spear if he dare. I ween that at break of day, he shall be among
+the first to fall and many another of his comrades round him.
+Would that I were as sure of being immortal and never growing
+old, and of being worshipped like Minerva and Apollo, as I am
+that this day will bring evil to the Argives."
+</para>
+
+<para>
+Thus spoke Hector and the Trojans shouted applause. They took
+their sweating steeds from under the yoke, and made them fast
+each by his own chariot. They made haste to bring sheep and
+cattle from the city, they brought wine also and corn from their
+houses and gathered much wood. They then offered unblemished
+hecatombs to the immortals, and the wind carried the sweet savour
+of sacrifice to heaven--but the blessed gods partook not thereof,
+for they bitterly hated Ilius with Priam and Priam's people. Thus
+high in hope they sat through the livelong night by the highways
+of war, and many a watchfire did they kindle. As when the stars
+shine clear, and the moon is bright--there is not a breath of
+air, not a peak nor glade nor jutting headland but it stands out
+in the ineffable radiance that breaks from the serene of heaven;
+the stars can all of them be told and the heart of the shepherd
+is glad--even thus shone the watchfires of the Trojans before
+Ilius midway between the ships and the river Xanthus. A thousand
+camp-fires gleamed upon the plain, and in the glow of each there
+sat fifty men, while the horses, champing oats and corn beside
+their chariots, waited till dawn should come.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK IX</title>
+
+<para>
+THUS did the Trojans watch. But Panic, comrade of blood-stained
+Rout, had taken fast hold of the Achaeans, and their princes were
+all of them in despair. As when the two winds that blow from
+Thrace--the north and the northwest--spring up of a sudden and
+rouse the fury of the main--in a moment the dark waves uprear
+their heads and scatter their sea-wrack in all directions--even
+thus troubled were the hearts of the Achaeans.
+</para>
+
+<para>
+The son of Atreus in dismay bade the heralds call the people to a
+council man by man, but not to cry the matter aloud; he made
+haste also himself to call them, and they sat sorry at heart in
+their assembly. Agamemnon shed tears as it were a running stream
+or cataract on the side of some sheer cliff; and thus, with many
+a heavy sigh he spoke to the Achaeans. "My friends," said he,
+"princes and councillors Of the Argives, the hand of heaven has
+been laid heavily upon me. Cruel Jove gave me his solemn promise
+that I should sack the city of Troy before returning, but he has
+played me false, and is now bidding me go ingloriously back to
+Argos with the loss of much people. Such is the will of Jove, who
+has laid many a proud city in the dust as he will yet lay others,
+for his power is above all. Now, therefore, let us all do as I
+say and sail back to our own country, for we shall not take
+Troy."
+</para>
+
+<para>
+Thus he spoke, and the sons of the Achaeans for a long while sat
+sorrowful there, but they all held their peace, till at last
+Diomed of the loud battle-cry made answer saying, "Son of Atreus,
+I will chide your folly, as is my right in council. Be not then
+aggrieved that I should do so. In the first place you attacked me
+before all the Danaans and said that I was a coward and no
+soldier. The Argives young and old know that you did so. But the
+son of scheming Saturn endowed you by halves only. He gave you
+honour as the chief ruler over us, but valour, which is the
+highest both right and might he did not give you. Sir, think you
+that the sons of the Achaeans are indeed as unwarlike and
+cowardly as you say they are? If your own mind is set upon going
+home--go--the way is open to you; the many ships that followed
+you from Mycene stand ranged upon the seashore; but the rest of
+us stay here till we have sacked Troy. Nay though these too
+should turn homeward with their ships, Sthenelus and myself will
+still fight on till we reach the goal of Ilius, for heaven was
+with us when we came."
+</para>
+
+<para>
+The sons of the Achaeans shouted applause at the words of Diomed,
+and presently Nestor rose to speak. "Son of Tydeus," said he, "in
+war your prowess is beyond question, and in council you excel all
+who are of your own years; no one of the Achaeans can make light
+of what you say nor gainsay it, but you have not yet come to the
+end of the whole matter. You are still young--you might be the
+youngest of my own children--still you have spoken wisely and
+have counselled the chief of the Achaeans not without discretion;
+nevertheless I am older than you and I will tell you everything;
+therefore let no man, not even King Agamemnon, disregard my
+saying, for he that foments civil discord is a clanless,
+hearthless outlaw.
+</para>
+
+<para>
+"Now, however, let us obey the behests of night and get our
+suppers, but let the sentinels every man of them camp by the
+trench that is without the wall. I am giving these instructions
+to the young men; when they have been attended to, do you, son of
+Atreus, give your orders, for you are the most royal among us
+all. Prepare a feast for your councillors; it is right and
+reasonable that you should do so; there is abundance of wine in
+your tents, which the ships of the Achaeans bring from Thrace
+daily. You have everything at your disposal wherewith to
+entertain guests, and you have many subjects. When many are got
+together, you can be guided by him whose counsel is wisest--and
+sorely do we need shrewd and prudent counsel, for the foe has lit
+his watchfires hard by our ships. Who can be other than dismayed?
+This night will either be the ruin of our host, or save it."
+</para>
+
+<para>
+Thus did he speak, and they did even as he had said. The
+sentinels went out in their armour under command of Nestor's son
+Thrasymedes, a captain of the host, and of the bold warriors
+Ascalaphus and Ialmenus: there were also Meriones, Aphareus and
+Deipyrus, and the son of Creion, noble Lycomedes. There were
+seven captains of the sentinels, and with each there went a
+hundred youths armed with long spears: they took their places
+midway between the trench and the wall, and when they had done so
+they lit their fires and got every man his supper.
+</para>
+
+<para>
+The son of Atreus then bade many councillors of the Achaeans to
+his quarters prepared a great feast in their honour. They laid
+their hands on the good things that were before them, and as soon
+as they had enough to eat and drink, old Nestor, whose counsel
+was ever truest, was the first to lay his mind before them. He,
+therefore, with all sincerity and goodwill addressed them thus.
+</para>
+
+<para>
+"With yourself, most noble son of Atreus, king of men, Agamemnon,
+will I both begin my speech and end it, for you are king over
+much people. Jove, moreover, has vouchsafed you to wield the
+sceptre and to uphold righteousness, that you may take thought
+for your people under you; therefore it behooves you above all
+others both to speak and to give ear, and to out the counsel of
+another who shall have been minded to speak wisely. All turns on
+you and on your commands, therefore I will say what I think will
+be best. No man will be of a truer mind than that which has been
+mine from the hour when you, sir, angered Achilles by taking the
+girl Briseis from his tent against my judgment. I urged you not
+to do so, but you yielded to your own pride, and dishonoured a
+hero whom heaven itself had honoured--for you still hold the
+prize that had been awarded to him. Now, however, let us think
+how we may appease him, both with presents and fair speeches that
+may conciliate him."
+</para>
+
+<para>
+And King Agamemnon answered, "Sir, you have reproved my folly
+justly. I was wrong. I own it. One whom heaven befriends is in
+himself a host, and Jove has shown that he befriends this man by
+destroying much people of the Achaeans. I was blinded with
+passion and yielded to my worser mind; therefore I will make
+amends, and will give him great gifts by way of atonement. I will
+tell them in the presence of you all. I will give him seven
+tripods that have never yet been on the fire, and ten talents of
+gold. I will give him twenty iron cauldrons and twelve strong
+horses that have won races and carried off prizes. Rich, indeed,
+both in land and gold is he that has as many prizes as my horses
+have won me. I will give him seven excellent workwomen, Lesbians,
+whom I chose for myself when he took Lesbos--all of surpassing
+beauty. I will give him these, and with them her whom I erewhile
+took from him, the daughter of Briseus; and I swear a great oath
+that I never went up into her couch, nor have been with her after
+the manner of men and women.
+</para>
+
+<para>
+"All these things will I give him now, and if hereafter the gods
+vouchsafe me to sack the city of Priam, let him come when we
+Achaeans are dividing the spoil, and load his ship with gold and
+bronze to his liking; furthermore let him take twenty Trojan
+women, the loveliest after Helen herself. Then, when we reach
+Achaean Argos, wealthiest of all lands, he shall be my son-in-law
+and I will show him like honour with my own dear son Orestes, who
+is being nurtured in all abundance. I have three daughters,
+Chrysothemis, Laodice, and lphianassa, let him take the one of
+his choice, freely and without gifts of wooing, to the house of
+Peleus; I will add such dower to boot as no man ever yet gave his
+daughter, and will give him seven well established cities,
+Cardamyle, Enope, and Hire, where there is grass; holy Pherae and
+the rich meadows of Anthea; Aepea also, and the vine-clad slopes
+of Pedasus, all near the sea, and on the borders of sandy Pylos.
+The men that dwell there are rich in cattle and sheep; they will
+honour him with gifts as though he were a god, and be obedient to
+his comfortable ordinances. All this will I do if he will now
+forgo his anger. Let him then yield; it is only Hades who is
+utterly ruthless and unyielding--and hence he is of all gods the
+one most hateful to mankind. Moreover I am older and more royal
+than himself. Therefore, let him now obey me."
+</para>
+
+<para>
+Then Nestor answered, "Most noble son of Atreus, king of men,
+Agamemnon. The gifts you offer are no small ones, let us then
+send chosen messengers, who may go to the tent of Achilles son of
+Peleus without delay. Let those go whom I shall name. Let
+Phoenix, dear to Jove, lead the way; let Ajax and Ulysses follow,
+and let the heralds Odius and Eurybates go with them. Now bring
+water for our hands, and bid all keep silence while we pray to
+Jove the son of Saturn, if so be that he may have mercy upon us."
+</para>
+
+<para>
+Thus did he speak, and his saying pleased them well.
+Men-servants poured water over the hands of the guests, while
+pages filled the mixing-bowls with wine and water, and handed it
+round after giving every man his drink-offering; then, when they
+had made their offerings, and had drunk each as much as he was
+minded, the envoys set out from the tent of Agamemnon son of
+Atreus; and Nestor, looking first to one and then to another, but
+most especially at Ulysses, was instant with them that they
+should prevail with the noble son of Peleus.
+</para>
+
+<para>
+They went their way by the shore of the sounding sea, and prayed
+earnestly to earth-encircling Neptune that the high spirit of the
+son of Aeacus might incline favourably towards them. When they
+reached the ships and tents of the Myrmidons, they found Achilles
+playing on a lyre, fair, of cunning workmanship, and its
+cross-bar was of silver. It was part of the spoils which he had
+taken when he sacked the city of Eetion, and he was now diverting
+himself with it and singing the feats of heroes. He was alone
+with Patroclus, who sat opposite to him and said nothing, waiting
+till he should cease singing. Ulysses and Ajax now came in--
+Ulysses leading the way--and stood before him. Achilles sprang
+from his seat with the lyre still in his hand, and Patroclus,
+when he saw the strangers, rose also. Achilles then greeted them
+saying, "All hail and welcome--you must come upon some great
+matter, you, who for all my anger are still dearest to me of the
+Achaeans."
+</para>
+
+<para>
+With this he led them forward, and bade them sit on seats covered
+with purple rugs; then he said to Patroclus who was close by him,
+"Son of Menoetius, set a larger bowl upon the table, mix less
+water with the wine, and give every man his cup, for these are
+very dear friends, who are now under my roof."
+</para>
+
+<para>
+Patroclus did as his comrade bade him; he set the chopping-block
+in front of the fire, and on it he laid the loin of a sheep, the
+loin also of a goat, and the chine of a fat hog. Automedon held
+the meat while Achilles chopped it; he then sliced the pieces and
+put them on spits while the son of Menoetius made the fire burn
+high. When the flame had died down, he spread the embers, laid
+the spits on top of them, lifting them up and setting them upon
+the spit-racks; and he sprinkled them with salt. When the meat
+was roasted, he set it on platters, and handed bread round the
+table in fair baskets, while Achilles dealt them their portions.
+Then Achilles took his seat facing Ulysses against the opposite
+wall, and bade his comrade Patroclus offer sacrifice to the gods;
+so he cast the offerings into the fire, and they laid their hands
+upon the good things that were before them. As soon as they had
+had enough to eat and drink, Ajax made a sign to Phoenix, and
+when he saw this, Ulysses filled his cup with wine and pledged
+Achilles.
+</para>
+
+<para>
+"Hail," said he, "Achilles, we have had no scant of good cheer,
+neither in the tent of Agamemnon, nor yet here; there has been
+plenty to eat and drink, but our thought turns upon no such
+matter. Sir, we are in the face of great disaster, and without
+your help know not whether we shall save our fleet or lose it.
+The Trojans and their allies have camped hard by our ships and by
+the wall; they have lit watchfires throughout their host and deem
+that nothing can now prevent them from falling on our fleet.
+Jove, moreover, has sent his lightnings on their right; Hector,
+in all his glory, rages like a maniac; confident that Jove is
+with him he fears neither god nor man, but is gone raving mad,
+and prays for the approach of day. He vows that he will hew the
+high sterns of our ships in pieces, set fire to their hulls, and
+make havoc of the Achaeans while they are dazed and smothered in
+smoke; I much fear that heaven will make good his boasting, and
+it will prove our lot to perish at Troy far from our home in
+Argos. Up, then, and late though it be, save the sons of the
+Achaeans who faint before the fury of the Trojans. You will
+repent bitterly hereafter if you do not, for when the harm is
+done there will be no curing it; consider ere it be too late, and
+save the Danaans from destruction.
+</para>
+
+<para>
+"My good friend, when your father Peleus sent you from Phthia to
+Agamemnon, did he not charge you saying, 'Son, Minerva and Juno
+will make you strong if they choose, but check your high temper,
+for the better part is in goodwill. Eschew vain quarrelling, and
+the Achaeans old and young will respect you more for doing so.'
+These were his words, but you have forgotten them. Even now,
+however, be appeased, and put away your anger from you. Agamemnon
+will make you great amends if you will forgive him; listen, and I
+will tell you what he has said in his tent that he will give you.
+He will give you seven tripods that have never yet been on the
+fire, and ten talents of gold; twenty iron cauldrons, and twelve
+strong horses that have won races and carried off prizes. Rich
+indeed both in land and gold is he who has as many prizes as
+these horses have won for Agamemnon. Moreover he will give you
+seven excellent workwomen, Lesbians, whom he chose for himself,
+when you took Lesbos--all of surpassing beauty. He will give you
+these, and with them her whom he erewhile took from you, the
+daughter of Briseus, and he will swear a great oath, he has never
+gone up into her couch nor been with her after the manner of men
+and women. All these things will he give you now down, and if
+hereafter the gods vouchsafe him to sack the city of Priam, you
+can come when we Achaeans are dividing the spoil, and load your
+ship with gold and bronze to your liking. You can take twenty
+Trojan women, the loveliest after Helen herself. Then, when we
+reach Achaean Argos, wealthiest of all lands, you shall be his
+son-in-law, and he will show you like honour with his own dear
+son Orestes, who is being nurtured in all abundance. Agamemnon
+has three daughters, Chrysothemis, Laodice, and Iphianassa; you
+may take the one of your choice, freely and without gifts of
+wooing, to the house of Peleus; he will add such dower to boot as
+no man ever yet gave his daughter, and will give you seven
+well-established cities, Cardamyle, Enope, and Hire where there
+is grass; holy Pheras and the rich meadows of Anthea; Aepea also,
+and the vine-clad slopes of Pedasus, all near the sea, and on the
+borders of sandy Pylos. The men that dwell there are rich in
+cattle and sheep; they will honour you with gifts as though were
+a god, and be obedient to your comfortable ordinances. All this
+will he do if you will now forgo your anger. Moreover, though you
+hate both him and his gifts with all your heart, yet pity the
+rest of the Achaeans who are being harassed in all their host;
+they will honour you as a god, and you will earn great glory at
+their hands. You might even kill Hector; he will come within your
+reach, for he is infatuated, and declares that not a Danaan whom
+the ships have brought can hold his own against him."
+</para>
+
+<para>
+Achilles answered, "Ulysses, noble son of Laertes, I should give
+you formal notice plainly and in all fixity of purpose that there
+be no more of this cajoling, from whatsoever quarter it may come.
+Him do I hate even as the gates of hell who says one thing while
+he hides another in his heart; therefore I will say what I mean.
+I will be appeased neither by Agamemnon son of Atreus nor by any
+other of the Danaans, for I see that I have no thanks for all my
+fighting. He that fights fares no better than he that does not;
+coward and hero are held in equal honour, and death deals like
+measure to him who works and him who is idle. I have taken
+nothing by all my hardships--with my life ever in my hand; as a
+bird when she has found a morsel takes it to her nestlings, and
+herself fares hardly, even so many a long night have I been
+wakeful, and many a bloody battle have I waged by day against
+those who were fighting for their women. With my ships I have
+taken twelve cities, and eleven round about Troy have I stormed
+with my men by land; I took great store of wealth from every one
+of them, but I gave all up to Agamemnon son of Atreus. He stayed
+where he was by his ships, yet of what came to him he gave
+little, and kept much himself.
+</para>
+
+<para>
+"Nevertheless he did distribute some meeds of honour among the
+chieftains and kings, and these have them still; from me alone of
+the Achaeans did he take the woman in whom I delighted--let him
+keep her and sleep with her. Why, pray, must the Argives needs
+fight the Trojans? What made the son of Atreus gather the host
+and bring them? Was it not for the sake of Helen? Are the sons of
+Atreus the only men in the world who love their wives? Any man of
+common right feeling will love and cherish her who is his own, as
+I this woman, with my whole heart, though she was but a fruitling
+of my spear. Agamemnon has taken her from me; he has played me
+false; I know him; let him tempt me no further, for he shall not
+move me. Let him look to you, Ulysses, and to the other princes
+to save his ships from burning. He has done much without me
+already. He has built a wall; he has dug a trench deep and wide
+all round it, and he has planted it within with stakes; but even
+so he stays not the murderous might of Hector. So long as I
+fought the Achaeans Hector suffered not the battle range far from
+the city walls; he would come to the Scaean gates and to the oak
+tree, but no further. Once he stayed to meet me and hardly did he
+escape my onset: now, however, since I am in no mood to fight
+him, I will to-morrow offer sacrifice to Jove and to all the
+gods; I will draw my ships into the water and then victual them
+duly; to-morrow morning, if you care to look, you will see my
+ships on the Hellespont, and my men rowing out to sea with might
+and main. If great Neptune vouchsafes me a fair passage, in three
+days I shall be in Phthia. I have much there that I left behind
+me when I came here to my sorrow, and I shall bring back still
+further store of gold, of red copper, of fair women, and of iron,
+my share of the spoils that we have taken; but one prize, he who
+gave has insolently taken away. Tell him all as I now bid you,
+and tell him in public that the Achaeans may hate him and beware
+of him should he think that he can yet dupe others for his
+effrontery never fails him.
+</para>
+
+<para>
+"As for me, hound that he is, he dares not look me in the face.
+I will take no counsel with him, and will undertake nothing in
+common with him. He has wronged me and deceived me enough, he
+shall not cozen me further; let him go his own way, for Jove has
+robbed him of his reason. I loathe his presents, and for himself
+care not one straw. He may offer me ten or even twenty times what
+he has now done, nay--not though it be all that he has in the
+world, both now or ever shall have; he may promise me the wealth
+of Orchomenus or of Egyptian Thebes, which is the richest city in
+the whole world, for it has a hundred gates through each of which
+two hundred men may drive at once with their chariots and horses;
+he may offer me gifts as the sands of the sea or the dust of the
+plain in multitude, but even so he shall not move me till I have
+been revenged in full for the bitter wrong he has done me. I will
+not marry his daughter; she may be fair as Venus, and skilful as
+Minerva, but I will have none of her: let another take her, who
+may be a good match for her and who rules a larger kingdom. If
+the gods spare me to return home, Peleus will find me a wife;
+there are Achaean women in Hellas and Phthia, daughters of kings
+that have cities under them; of these I can take whom I will and
+marry her. Many a time was I minded when at home in Phthia to woo
+and wed a woman who would make me a suitable wife, and to enjoy
+the riches of my old father Peleus. My life is more to me than
+all the wealth of Ilius while it was yet at peace before the
+Achaeans went there, or than all the treasure that lies on the
+stone floor of Apollo's temple beneath the cliffs of Pytho.
+Cattle and sheep are to be had for harrying, and a man buy both
+tripods and horses if he wants them, but when his life has once
+left him it can neither be bought nor harried back again.
+</para>
+
+<para>
+"My mother Thetis tells me that there are two ways in which I may
+meet my end. If I stay here and fight, I shall not return alive
+but my name will live for ever: whereas if I go home my name will
+die, but it will be long ere death shall take me. To the rest of
+you, then, I say, 'Go home, for you will not take Ilius.' Jove
+has held his hand over her to protect her, and her people have
+taken heart. Go, therefore, as in duty bound, and tell the
+princes of the Achaeans the message that I have sent them; tell
+them to find some other plan for the saving of their ships and
+people, for so long as my displeasure lasts the one that they
+have now hit upon may not be. As for Phoenix, let him sleep here
+that he may sail with me in the morning if he so will. But I
+will not take him by force."
+</para>
+
+<para>
+They all held their peace, dismayed at the sternness with which
+he had denied them, till presently the old knight Phoenix in his
+great fear for the ships of the Achaeans, burst into tears and
+said, "Noble Achilles, if you are now minded to return, and in
+the fierceness of your anger will do nothing to save the ships
+from burning, how, my son, can I remain here without you? Your
+father Peleus bade me go with you when he sent you as a mere lad
+from Phthia to Agamemnon. You knew nothing neither of war nor of
+the arts whereby men make their mark in council, and he sent me
+with you to train you in all excellence of speech and action.
+Therefore, my son, I will not stay here without you--no, not
+though heaven itself vouchsafe to strip my years from off me, and
+make me young as I was when I first left Hellas the land of fair
+women. I was then flying the anger of father Amyntor, son of
+Ormenus, who was furious with me in the matter of his concubine,
+of whom he was enamoured to the wronging of his wife my mother.
+My mother, therefore, prayed me without ceasing to lie with the
+woman myself, that so she hate my father, and in the course of
+time I yielded. But my father soon came to know, and cursed me
+bitterly, calling the dread Erinyes to witness. He prayed that no
+son of mine might ever sit upon knees--and the gods, Jove of the
+world below and awful Proserpine, fulfilled his curse. I took
+counsel to kill him, but some god stayed my rashness and bade me
+think on men's evil tongues and how I should be branded as the
+murderer of my father; nevertheless I could not bear to stay in
+my father's house with him so bitter a against me. My cousins and
+clansmen came about me, and pressed me sorely to remain; many a
+sheep and many an ox did they slaughter, and many a fat hog did
+they set down to roast before the fire; many a jar, too, did they
+broach of my father's wine. Nine whole nights did they set a
+guard over me taking it in turns to watch, and they kept a fire
+always burning, both in the cloister of the outer court and in
+the inner court at the doors of the room wherein I lay; but when
+the darkness of the tenth night came, I broke through the closed
+doors of my room, and climbed the wall of the outer court after
+passing quickly and unperceived through the men on guard and the
+women servants. I then fled through Hellas till I came to fertile
+Phthia, mother of sheep, and to King Peleus, who made me welcome
+and treated me as a father treats an only son who will be heir to
+all his wealth. He made me rich and set me over much people,
+establishing me on the borders of Phthia where I was chief ruler
+over the Dolopians.
+</para>
+
+<para>
+"It was I, Achilles, who had the making of you; I loved you with
+all my heart: for you would eat neither at home nor when you had
+gone out elsewhere, till I had first set you upon my knees, cut
+up the dainty morsel that you were to eat, and held the wine-cup
+to your lips. Many a time have you slobbered your wine in baby
+helplessness over my shirt; I had infinite trouble with you, but
+I knew that heaven had vouchsafed me no offspring of my own, and
+I made a son of you, Achilles, that in my hour of need you might
+protect me. Now, therefore, I say battle with your pride and beat
+it; cherish not your anger for ever; the might and majesty of
+heaven are more than ours, but even heaven may be appeased; and
+if a man has sinned he prays the gods, and reconciles them to
+himself by his piteous cries and by frankincense, with
+drink-offerings and the savour of burnt sacrifice. For prayers
+are as daughters to great Jove; halt, wrinkled, with eyes
+askance, they follow in the footsteps of sin, who, being fierce
+and fleet of foot, leaves them far behind him, and ever baneful
+to mankind outstrips them even to the ends of the world; but
+nevertheless the prayers come hobbling and healing after. If a
+man has pity upon these daughters of Jove when they draw near
+him, they will bless him and hear him too when he is praying; but
+if he deny them and will not listen to them, they go to Jove the
+son of Saturn and pray that he may presently fall into sin--to
+his ruing bitterly hereafter. Therefore, Achilles, give these
+daughters of Jove due reverence, and bow before them as all good
+men will bow. Were not the son of Atreus offering you gifts and
+promising others later--if he were still furious and implacable--
+I am not he that would bid you throw off your anger and help the
+Achaeans, no matter how great their need; but he is giving much
+now, and more hereafter; he has sent his captains to urge his
+suit, and has chosen those who of all the Argives are most
+acceptable to you; make not then their words and their coming to
+be of none effect. Your anger has been righteous so far. We have
+heard in song how heroes of old time quarrelled when they were
+roused to fury, but still they could be won by gifts, and fair
+words could soothe them.
+</para>
+
+<para>
+"I have an old story in my mind--a very old one--but you are all
+friends and I will tell it. The Curetes and the Aetolians were
+fighting and killing one another round Calydon--the Aetolians
+defending the city and the Curetes trying to destroy it. For
+Diana of the golden throne was angry and did them hurt because
+Oeneus had not offered her his harvest first-fruits. The other
+gods had all been feasted with hecatombs, but to the daughter of
+great Jove alone he had made no sacrifice. He had forgotten her,
+or somehow or other it had escaped him, and this was a grievous
+sin. Thereon the archer goddess in her displeasure sent a
+prodigious creature against him--a savage wild boar with great
+white tusks that did much harm to his orchard lands, uprooting
+apple-trees in full bloom and throwing them to the ground. But
+Meleager son of Oeneus got huntsmen and hounds from many cities
+and killed it--for it was so monstrous that not a few were
+needed, and many a man did it stretch upon his funeral pyre. On
+this the goddess set the Curetes and the Aetolians fighting
+furiously about the head and skin of the boar.
+</para>
+
+<para>
+"So long as Meleager was in the field things went badly with the
+Curetes, and for all their numbers they could not hold their
+ground under the city walls; but in the course of time Meleager
+was angered as even a wise man will sometimes be. He was incensed
+with his mother Althaea, and therefore stayed at home with his
+wedded wife fair Cleopatra, who was daughter of Marpessa daughter
+of Euenus, and of Ides the man then living. He it was who took
+his bow and faced King Apollo himself for fair Marpessa's sake;
+her father and mother then named her Alcyone, because her mother
+had mourned with the plaintive strains of the halcyon-bird when
+Phoebus Apollo had carried her off. Meleager, then, stayed at
+home with Cleopatra, nursing the anger which he felt by reason of
+his mother's curses. His mother, grieving for the death of her
+brother, prayed the gods, and beat the earth with her hands,
+calling upon Hades and on awful Proserpine; she went down upon
+her knees and her bosom was wet with tears as she prayed that
+they would kill her son--and Erinys that walks in darkness and
+knows no ruth heard her from Erebus.
+</para>
+
+<para>
+"Then was heard the din of battle about the gates of Calydon, and
+the dull thump of the battering against their walls. Thereon the
+elders of the Aetolians besought Meleager; they sent the chiefest
+of their priests, and begged him to come out and help them,
+promising him a great reward. They bade him choose fifty
+plough-gates, the most fertile in the plain of Calydon, the
+one-half vineyard and the other open plough-land. The old warrior
+Oeneus implored him, standing at the threshold of his room and
+beating the doors in supplication. His sisters and his mother
+herself besought him sore, but he the more refused them; those of
+his comrades who were nearest and dearest to him also prayed him,
+but they could not move him till the foe was battering at the
+very doors of his chamber, and the Curetes had scaled the walls
+and were setting fire to the city. Then at last his sorrowing
+wife detailed the horrors that befall those whose city is taken;
+she reminded him how the men are slain, and the city is given
+over to the flames, while the women and children are carried into
+captivity; when he heard all this, his heart was touched, and he
+donned his armour to go forth. Thus of his own inward motion he
+saved the city of the Aetolians; but they now gave him nothing of
+those rich rewards that they had offered earlier, and though he
+saved the city he took nothing by it. Be not then, my son, thus
+minded; let not heaven lure you into any such course. When the
+ships are burning it will be a harder matter to save them. Take
+the gifts, and go, for the Achaeans will then honour you as a
+god; whereas if you fight without taking them, you may beat the
+battle back, but you will not be held in like honour."
+</para>
+
+<para>
+And Achilles answered, "Phoenix, old friend and father, I have no
+need of such honour. I have honour from Jove himself, which will
+abide with me at my ships while I have breath in my body, and my
+limbs are strong. I say further--and lay my saying to your
+heart--vex me no more with this weeping and lamentation, all in
+the cause of the son of Atreus. Love him so well, and you may
+lose the love I bear you. You ought to help me rather in
+troubling those that trouble me; be king as much as I am, and
+share like honour with myself; the others shall take my answer;
+stay here yourself and sleep comfortably in your bed; at daybreak
+we will consider whether to remain or go."
+</para>
+
+<para>
+On this she nodded quietly to Patroclus as a sign that he was to
+prepare a bed for Phoenix, and that the others should take their
+leave. Ajax son of Telamon then said, "Ulysses, noble son of
+Laertes, let us be gone, for I see that our journey is vain. We
+must now take our answer, unwelcome though it be, to the Danaans
+who are waiting to receive it. Achilles is savage and
+remorseless; he is cruel, and cares nothing for the love his
+comrades lavished upon him more than on all the others. He is
+implacable--and yet if a man's brother or son has been slain he
+will accept a fine by way of amends from him that killed him, and
+the wrong-doer having paid in full remains in peace among his own
+people; but as for you, Achilles, the gods have put a wicked
+unforgiving spirit in your heart, and this, all about one single
+girl, whereas we now offer you the seven best we have, and much
+else into the bargain. Be then of a more gracious mind, respect
+the hospitality of your own roof. We are with you as messengers
+from the host of the Danaans, and would fain he held nearest and
+dearest to yourself of all the Achaeans."
+</para>
+
+<para>
+"Ajax," replied Achilles, "noble son of Telamon, you have spoken
+much to my liking, but my blood boils when I think it all over,
+and remember how the son of Atreus treated me with contumely as
+though I were some vile tramp, and that too in the presence of
+the Argives. Go, then, and deliver your message; say that I will
+have no concern with fighting till Hector, son of noble Priam,
+reaches the tents of the Myrmidons in his murderous course, and
+flings fire upon their ships. For all his lust of battle, I take
+it he will be held in check when he is at my own tent and ship."
+</para>
+
+<para>
+On this they took every man his double cup, made their
+drink-offerings, and went back to the ships, Ulysses leading the
+way. But Patroclus told his men and the maid-servants to make
+ready a comfortable bed for Phoenix; they therefore did so with
+sheepskins, a rug, and a sheet of fine linen. The old man then
+laid himself down and waited till morning came. But Achilles
+slept in an inner room, and beside him the daughter of Phorbas
+lovely Diomede, whom he had carried off from Lesbos. Patroclus
+lay on the other side of the room, and with him fair Iphis whom
+Achilles had given him when he took Scyros the city of Enyeus.
+</para>
+
+<para>
+When the envoys reached the tents of the son of Atreus, the
+Achaeans rose, pledged them in cups of gold, and began to
+question them. King Agamemnon was the first to do so. "Tell me,
+Ulysses," said he, "will he save the ships from burning, or did
+be refuse, and is he still furious?"
+</para>
+
+<para>
+Ulysses answered, "Most noble son of Atreus, king of men,
+Agamemnon, Achilles will not be calmed, but is more fiercely
+angry than ever, and spurns both you and your gifts. He bids you
+take counsel with the Achaeans to save the ships and host as you
+best may; as for himself, he said that at daybreak he should draw
+his ships into the water. He said further that he should advise
+every one to sail home likewise, for that you will not reach the
+goal of Ilius. 'Jove,' he said, 'has laid his hand over the city
+to protect it, and the people have taken heart.' This is what he
+said, and the others who were with me can tell you the same
+story--Ajax and the two heralds, men, both of them, who may be
+trusted. The old man Phoenix stayed where he was to sleep, for so
+Achilles would have it, that he might go home with him in the
+morning if he so would; but he will not take him by force."
+</para>
+
+<para>
+They all held their peace, sitting for a long time silent and
+dejected, by reason of the sternness with which Achilles had
+refused them, till presently Diomed said, "Most noble son of
+Atreus, king of men, Agamemnon, you ought not to have sued the
+son of Peleus nor offered him gifts. He is proud enough as it is,
+and you have encouraged him in his pride still further. Let him
+stay or go as he will. He will fight later when he is in the
+humour, and heaven puts it in his mind to do so. Now, therefore,
+let us all do as I say; we have eaten and drunk our fill, let us
+then take our rest, for in rest there is both strength and stay.
+But when fair rosy-fingered morn appears, forthwith bring out
+your host and your horsemen in front of the ships, urging them
+on, and yourself fighting among the foremost."
+</para>
+
+<para>
+Thus he spoke, and the other chieftains approved his words. They
+then made their drink-offerings and went every man to his own
+tent, where they laid down to rest and enjoyed the boon of sleep.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK X</title>
+
+<para>
+NOW the other princes of the Achaeans slept soundly the whole
+night through, but Agamemnon son of Atreus was troubled, so that
+he could get no rest. As when fair Juno's lord flashes his
+lightning in token of great rain or hail or snow when the
+snow-flakes whiten the ground, or again as a sign that he will
+open the wide jaws of hungry war, even so did Agamemnon heave
+many a heavy sigh, for his soul trembled within him. When he
+looked upon the plain of Troy he marvelled at the many watchfires
+burning in front of Ilius, and at the sound of pipes and flutes
+and of the hum of men, but when presently he turned towards the
+ships and hosts of the Achaeans, he tore his hair by handfuls
+before Jove on high, and groaned aloud for the very disquietness
+of his soul. In the end he deemed it best to go at once to Nestor
+son of Neleus, and see if between them they could find any way of
+the Achaeans from destruction. He therefore rose, put on his
+shirt, bound his sandals about his comely feet, flung the skin of
+a huge tawny lion over his shoulders--a skin that reached his
+feet--and took his spear in his hand.
+</para>
+
+<para>
+Neither could Menelaus sleep, for he, too, boded ill for the
+Argives who for his sake had sailed from far over the seas to
+fight the Trojans. He covered his broad back with the skin of a
+spotted panther, put a casque of bronze upon his head, and took
+his spear in his brawny hand. Then he went to rouse his brother,
+who was by far the most powerful of the Achaeans, and was
+honoured by the people as though he were a god. He found him by
+the stern of his ship already putting his goodly array about his
+shoulders, and right glad was he that his brother had come.
+</para>
+
+<para>
+Menelaus spoke first. "Why," said he, "my dear brother, are you
+thus arming? Are you going to send any of our comrades to exploit
+the Trojans? I greatly fear that no one will do you this service,
+and spy upon the enemy alone in the dead of night. It will be a
+deed of great daring."
+</para>
+
+<para>
+And King Agamemnon answered, "Menelaus, we both of us need shrewd
+counsel to save the Argives and our ships, for Jove has changed
+his mind, and inclines towards Hector's sacrifices rather than
+ours. I never saw nor heard tell of any man as having wrought
+such ruin in one day as Hector has now wrought against the sons
+of the Achaeans--and that too of his own unaided self, for he is
+son neither to god nor goddess. The Argives will rue it long and
+deeply. Run, therefore, with all speed by the line of the ships,
+and call Ajax and Idomeneus. Meanwhile I will go to Nestor, and
+bid him rise and go about among the companies of our sentinels to
+give them their instructions; they will listen to him sooner than
+to any man, for his own son, and Meriones brother in arms to
+Idomeneus, are captains over them. It was to them more
+particularly that we gave this charge."
+</para>
+
+<para>
+Menelaus replied, "How do I take your meaning? Am I to stay with
+them and wait your coming, or shall I return here as soon as I
+have given your orders?" "Wait," answered King Agamemnon, "for
+there are so many paths about the camp that we might miss one
+another. Call every man on your way, and bid him be stirring;
+name him by his lineage and by his father's name, give each all
+titular observance, and stand not too much upon your own dignity;
+we must take our full share of toil, for at our birth Jove laid
+this heavy burden upon us."
+</para>
+
+<para>
+With these instructions he sent his brother on his way, and went
+on to Nestor shepherd of his people. He found him sleeping in his
+tent hard by his own ship; his goodly armour lay beside him--his
+shield, his two spears and his helmet; beside him also lay the
+gleaming girdle with which the old man girded himself when he
+armed to lead his people into battle--for his age stayed him not.
+He raised himself on his elbow and looked up at Agamemnon. "Who
+is it," said he, "that goes thus about the host and the ships
+alone and in the dead of night, when men are sleeping? Are you
+looking for one of your mules or for some comrade? Do not stand
+there and say nothing, but speak. What is your business?"
+</para>
+
+<para>
+And Agamemnon answered, "Nestor, son of Neleus, honour to the
+Achaean name, it is I, Agamemnon son of Atreus, on whom Jove has
+laid labour and sorrow so long as there is breath in my body and
+my limbs carry me. I am thus abroad because sleep sits not upon
+my eyelids, but my heart is big with war and with the jeopardy of
+the Achaeans. I am in great fear for the Danaans. I am at sea,
+and without sure counsel; my heart beats as though it would leap
+out of my body, and my limbs fail me. If then you can do
+anything--for you too cannot sleep--let us go the round of the
+watch, and see whether they are drowsy with toil and sleeping to
+the neglect of their duty. The enemy is encamped hard and we know
+not but he may attack us by night."
+</para>
+
+<para>
+Nestor replied, "Most noble son of Atreus, king of men,
+Agamemnon, Jove will not do all for Hector that Hector thinks he
+will; he will have troubles yet in plenty if Achilles will lay
+aside his anger. I will go with you, and we will rouse others,
+either the son of Tydeus, or Ulysses, or fleet Ajax and the
+valiant son of Phyleus. Some one had also better go and call Ajax
+and King Idomeneus, for their ships are not near at hand but the
+farthest of all. I cannot however refrain from blaming Menelaus,
+much as I love him and respect him--and I will say so plainly,
+even at the risk of offending you--for sleeping and leaving all
+this trouble to yourself. He ought to be going about imploring
+aid from all the princes of the Achaeans, for we are in extreme
+danger."
+</para>
+
+<para>
+And Agamemnon answered, "Sir, you may sometimes blame him justly,
+for he is often remiss and unwilling to exert himself--not
+indeed from sloth, nor yet heedlessness, but because he looks to
+me and expects me to take the lead. On this occasion, however, he
+was awake before I was, and came to me of his own accord. I have
+already sent him to call the very men whom you have named. And
+now let us be going. We shall find them with the watch outside
+the gates, for it was there I said that we would meet them."
+</para>
+
+<para>
+"In that case," answered Nestor, "the Argives will not blame him
+nor disobey his orders when he urges them to fight or gives them
+instructions."
+</para>
+
+<para>
+With this he put on his shirt, and bound his sandals about his
+comely feet. He buckled on his purple coat, of two thicknesses,
+large, and of a rough shaggy texture, grasped his redoubtable
+bronze-shod spear, and wended his way along the line of the
+Achaean ships. First he called loudly to Ulysses peer of gods in
+counsel and woke him, for he was soon roused by the sound of the
+battle-cry. He came outside his tent and said, "Why do you go
+thus alone about the host, and along the line of the ships in the
+stillness of the night? What is it that you find so urgent?" And
+Nestor knight of Gerene answered, "Ulysses, noble son of Laertes,
+take it not amiss, for the Achaeans are in great straits. Come
+with me and let us wake some other, who may advise well with us
+whether we shall fight or fly."
+</para>
+
+<para>
+On this Ulysses went at once into his tent, put his shield about
+his shoulders and came out with them. First they went to Diomed
+son of Tydeus, and found him outside his tent clad in his armour
+with his comrades sleeping round him and using their shields as
+pillows; as for their spears, they stood upright on the spikes of
+their butts that were driven into the ground, and the burnished
+bronze flashed afar like the lightning of father Jove. The hero
+was sleeping upon the skin of an ox, with a piece of fine carpet
+under his head; Nestor went up to him and stirred him with his
+heel to rouse him, upbraiding him and urging him to bestir
+himself. "Wake up," he exclaimed, "son of Tydeus. How can you
+sleep on in this way? Can you not see that the Trojans are
+encamped on the brow of the plain hard by our ships, with but a
+little space between us and them?"
+</para>
+
+<para>
+On these words Diomed leaped up instantly and said, "Old man,
+your heart is of iron; you rest not one moment from your labours.
+Are there no younger men among the Achaeans who could go about to
+rouse the princes? There is no tiring you."
+</para>
+
+<para>
+And Nestor knight of Gerene made answer, "My son, all that you
+have said is true. I have good sons, and also much people who
+might call the chieftains, but the Achaeans are in the gravest
+danger; life and death are balanced as it were on the edge of a
+razor. Go then, for you are younger than I, and of your courtesy
+rouse Ajax and the fleet son of Phyleus."
+</para>
+
+<para>
+Diomed threw the skin of a great tawny lion about his shoulders--
+a skin that reached his feet--and grasped his spear. When he had
+roused the heroes, he brought them back with him; they then went
+the round of those who were on guard, and found the captains not
+sleeping at their posts but wakeful and sitting with their arms
+about them. As sheep dogs that watch their flocks when they are
+yarded, and hear a wild beast coming through the mountain forest
+towards them--forthwith there is a hue and cry of dogs and men,
+and slumber is broken--even so was sleep chased from the eyes of
+the Achaeans as they kept the watches of the wicked night, for
+they turned constantly towards the plain whenever they heard any
+stir among the Trojans. The old man was glad bade them be of good
+cheer. "Watch on, my children," said he, "and let not sleep get
+hold upon you, lest our enemies triumph over us."
+</para>
+
+<para>
+With this he passed the trench, and with him the other chiefs of
+the Achaeans who had been called to the council. Meriones and the
+brave son of Nestor went also, for the princes bade them. When
+they were beyond the trench that was dug round the wall they held
+their meeting on the open ground where there was a space clear of
+corpses, for it was here that when night fell Hector had turned
+back from his onslaught on the Argives. They sat down, therefore,
+and held debate with one another.
+</para>
+
+<para>
+Nestor spoke first. "My friends," said he, "is there any man bold
+enough to venture the Trojans, and cut off some straggler, or us
+news of what the enemy mean to do whether they will stay here by
+the ships away from the city, or whether, now that they have
+worsted the Achaeans, they will retire within their walls. If he
+could learn all this and come back safely here, his fame would be
+high as heaven in the mouths of all men, and he would be rewarded
+richly; for the chiefs from all our ships would each of them give
+him a black ewe with her lamb--which is a present of surpassing
+value--and he would be asked as a guest to all feasts and
+clan-gatherings."
+</para>
+
+<para>
+They all held their peace, but Diomed of the loud war-cry spoke
+saying, "Nestor, gladly will I visit the host of the Trojans over
+against us, but if another will go with me I shall do so in
+greater confidence and comfort. When two men are together, one of
+them may see some opportunity which the other has not caught
+sight of; if a man is alone he is less full of resource, and his
+wit is weaker."
+</para>
+
+<para>
+On this several offered to go with Diomed. The two Ajaxes,
+servants of Mars, Meriones, and the son of Nestor all wanted to
+go, so did Menelaus son of Atreus; Ulysses also wished to go
+among the host of the Trojans, for he was ever full of daring,
+and thereon Agamemnon king of men spoke thus: "Diomed," said he,
+"son of Tydeus, man after my own heart, choose your comrade for
+yourself--take the best man of those that have offered, for many
+would now go with you. Do not through delicacy reject the better
+man, and take the worst out of respect for his lineage, because
+he is of more royal blood."
+</para>
+
+<para>
+He said this because he feared for Menelaus. Diomed answered, "If
+you bid me take the man of my own choice, how in that case can I
+fail to think of Ulysses, than whom there is no man more eager to
+face all kinds of danger--and Pallas Minerva loves him well? If
+he were to go with me we should pass safely through fire itself,
+for he is quick to see and understand."
+</para>
+
+<para>
+"Son of Tydeus," replied Ulysses, "say neither good nor ill about
+me, for you are among Argives who know me well. Let us be going,
+for the night wanes and dawn is at hand. The stars have gone
+forward, two-thirds of the night are already spent, and the third
+is alone left us."
+</para>
+
+<para>
+They then put on their armour. Brave Thrasymedes provided the son
+of Tydeus with a sword and a shield (for he had left his own at
+his ship) and on his head he set a helmet of bull's hide without
+either peak or crest; it is called a skull-cap and is a common
+headgear. Meriones found a bow and quiver for Ulysses, and on his
+head he set a leathern helmet that was lined with a strong
+plaiting of leathern thongs, while on the outside it was thickly
+studded with boar's teeth, well and skilfully set into it; next
+the head there was an inner lining of felt. This helmet had been
+stolen by Autolycus out of Eleon when he broke into the house of
+Amyntor son of Ormenus. He gave it to Amphidamas of Cythera to
+take to Scandea, and Amphidamas gave it as a guest-gift to Molus,
+who gave it to his son Meriones; and now it was set upon the head
+of Ulysses.
+</para>
+
+<para>
+When the pair had armed, they set out, and left the other
+chieftains behind them. Pallas Minerva sent them a heron by the
+wayside upon their right hands; they could not see it for the
+darkness, but they heard its cry. Ulysses was glad when he heard
+it and prayed to Minerva: "Hear me," he cried, "daughter of
+aegis-bearing Jove, you who spy out all my ways and who are with
+me in all my hardships; befriend me in this mine hour, and grant
+that we may return to the ships covered with glory after having
+achieved some mighty exploit that shall bring sorrow to the
+Trojans."
+</para>
+
+<para>
+Then Diomed of the loud war-cry also prayed: "Hear me too," said
+he, "daughter of Jove, unweariable; be with me even as you were
+with my noble father Tydeus when he went to Thebes as envoy sent
+by the Achaeans. He left the Achaeans by the banks of the river
+Aesopus, and went to the city bearing a message of peace to the
+Cadmeians; on his return thence, with your help, goddess, he did
+great deeds of daring, for you were his ready helper. Even so
+guide me and guard me now, and in return I will offer you in
+sacrifice a broad-browed heifer of a year old, unbroken, and
+never yet brought by man under the yoke. I will gild her horns
+and will offer her up to you in sacrifice."
+</para>
+
+<para>
+Thus they prayed, and Pallas Minerva heard their prayer. When
+they had done praying to the daughter of great Jove, they went
+their way like two lions prowling by night amid the armour and
+blood-stained bodies of them that had fallen.
+</para>
+
+<para>
+Neither again did Hector let the Trojans sleep; for he too called
+the princes and councillors of the Trojans that he might set his
+counsel before them. "Is there one," said he, "who for a great
+reward will do me the service of which I will tell you? He shall
+be well paid if he will. I will give him a chariot and a couple
+of horses, the fleetest that can be found at the ships of the
+Achaeans, if he will dare this thing; and he will win infinite
+honour to boot; he must go to the ships and find out whether they
+are still guarded as heretofore, or whether now that we have
+beaten them the Achaeans design to fly, and through sheer
+exhaustion are neglecting to keep their watches."
+</para>
+
+<para>
+They all held their peace; but there was among the Trojans a
+certain man named Dolon, son of Eumedes, the famous herald--a man
+rich in gold and bronze. He was ill-favoured, but a good runner,
+and was an only son among five sisters. He it was that now
+addressed the Trojans. "I, Hector," said he, "Will to the ships
+and will exploit them. But first hold up your sceptre and swear
+that you will give me the chariot, bedight with bronze, and the
+horses that now carry the noble son of Peleus. I will make you a
+good scout, and will not fail you. I will go through the host
+from one end to the other till I come to the ship of Agamemnon,
+where I take it the princes of the Achaeans are now consulting
+whether they shall fight or fly."
+</para>
+
+<para>
+When he had done speaking Hector held up his sceptre, and swore
+him his oath saying, "May Jove the thundering husband of Juno
+bear witness that no other Trojan but yourself shall mount those
+steeds, and that you shall have your will with them for ever."
+</para>
+
+<para>
+The oath he swore was bootless, but it made Dolon more keen on
+going. He hung his bow over his shoulder, and as an overall he
+wore the skin of a grey wolf, while on his head he set a cap of
+ferret skin. Then he took a pointed javelin, and left the camp
+for the ships, but he was not to return with any news for Hector.
+When he had left the horses and the troops behind him, he made
+all speed on his way, but Ulysses perceived his coming and said
+to Diomed, "Diomed, here is some one from the camp; I am not sure
+whether he is a spy, or whether it is some thief who would
+plunder the bodies of the dead; let him get a little past us, we
+can then spring upon him and take him. If, however, he is too
+quick for us, go after him with your spear and hem him in towards
+the ships away from the Trojan camp, to prevent his getting back
+to the town."
+</para>
+
+<para>
+With this they turned out of their way and lay down among the
+corpses. Dolon suspected nothing and soon passed them, but when
+he had got about as far as the distance by which a mule-plowed
+furrow exceeds one that has been ploughed by oxen (for mules can
+plow fallow land quicker than oxen) they ran after him, and when
+he heard their footsteps he stood still, for he made sure they
+were friends from the Trojan camp come by Hector's orders to bid
+him return; when, however, they were only a spear's cast, or less
+away form him, he saw that they were enemies as fast as his legs
+could take him. The others gave chase at once, and as a couple of
+well-trained hounds press forward after a doe or hare that runs
+screaming in front of them, even so did the son of Tydeus and
+Ulysses pursue Dolon and cut him off from his own people. But
+when he had fled so far towards the ships that he would soon have
+fallen in with the outposts, Minerva infused fresh strength into
+the son of Tydeus for fear some other of the Achaeans might have
+the glory of being first to hit him, and he might himself be only
+second; he therefore sprang forward with his spear and said,
+"Stand, or I shall throw my spear, and in that case I shall soon
+make an end of you."
+</para>
+
+<para>
+He threw as he spoke, but missed his aim on purpose. The dart
+flew over the man's right shoulder, and then stuck in the ground.
+He stood stock still, trembling and in great fear; his teeth
+chattered, and he turned pale with fear. The two came breathless
+up to him and seized his hands, whereon he began to weep and
+said, "Take me alive; I will ransom myself; we have great store
+of gold, bronze, and wrought iron, and from this my father will
+satisfy you with a very large ransom, should he hear of my being
+alive at the ships of the Achaeans."
+</para>
+
+<para>
+"Fear not," replied Ulysses, "let no thought of death be in your
+mind; but tell me, and tell me true, why are you thus going about
+alone in the dead of night away from your camp and towards the
+ships, while other men are sleeping? Is it to plunder the bodies
+of the slain, or did Hector send you to spy out what was going on
+at the ships? Or did you come here of your own mere notion?"
+</para>
+
+<para>
+Dolon answered, his limbs trembling beneath him: "Hector, with
+his vain flattering promises, lured me from my better judgement.
+He said he would give me the horses of the noble son of Peleus
+and his bronze-bedizened chariot; he bade me go through the
+darkness of the flying night, get close to the enemy, and find
+out whether the ships are still guarded as heretofore, or
+whether, now that we have beaten them, the Achaeans design to
+fly, and through sheer exhaustion are neglecting to keep their
+watches."
+</para>
+
+<para>
+Ulysses smiled at him and answered, "You had indeed set your
+heart upon a great reward, but the horses of the descendant of
+Aeacus are hardly to be kept in hand or driven by any other
+mortal man than Achilles himself, whose mother was an immortal.
+But tell me, and tell me true, where did you leave Hector when
+you started? Where lies his armour and his horses? How, too, are
+the watches and sleeping-ground of the Trojans ordered? What are
+their plans? Will they stay here by the ships and away from the
+city, or now that they have worsted the Achaeans, will they
+retire within their walls?"
+</para>
+
+<para>
+And Dolon answered, "I will tell you truly all. Hector and the
+other councillors are now holding conference by the monument of
+great Ilus, away from the general tumult; as for the guards about
+which you ask me, there is no chosen watch to keep guard over the
+host. The Trojans have their watchfires, for they are bound to
+have them; they, therefore, are awake and keep each other to
+their duty as sentinels; but the allies who have come from other
+places are asleep and leave it to the Trojans to keep guard, for
+their wives and children are not here."
+</para>
+
+<para>
+Ulysses then said, "Now tell me; are they sleeping among the
+Trojan troops, or do they lie apart? Explain this that I may
+understand it."
+</para>
+
+<para>
+"I will tell you truly all," replied Dolon. "To the seaward lie
+the Carians, the Paeonian bowmen, the Leleges, the Cauconians,
+and the noble Pelasgi. The Lysians and proud Mysians, with the
+Phrygians and Meonians, have their place on the side towards
+Thymbra; but why ask about an this? If you want to find your way
+into the host of the Trojans, there are the Thracians, who have
+lately come here and lie apart from the others at the far end of
+the camp; and they have Rhesus son of Eioneus for their king. His
+horses are the finest and strongest that I have ever seen, they
+are whiter than snow and fleeter than any wind that blows. His
+chariot is bedight with silver and gold, and he has brought his
+marvellous golden armour, of the rarest workmanship--too splendid
+for any mortal man to carry, and meet only for the gods. Now,
+therefore, take me to the ships or bind me securely here, until
+you come back and have proved my words whether they be false or
+true."
+</para>
+
+<para>
+Diomed looked sternly at him and answered, "Think not, Dolon, for
+all the good information you have given us, that you shall escape
+now you are in our hands, for if we ransom you or let you go, you
+will come some second time to the ships of the Achaeans either as
+a spy or as an open enemy, but if I kill you and an end of you,
+you will give no more trouble."
+</para>
+
+<para>
+On this Dolon would have caught him by the beard to beseech him
+further, but Diomed struck him in the middle of his neck with his
+sword and cut through both sinews so that his head fell rolling
+in the dust while he was yet speaking. They took the ferret-skin
+cap from his head, and also the wolf-skin, the bow, and his long
+spear. Ulysses hung them up aloft in honour of Minerva the
+goddess of plunder, and prayed saying, "Accept these, goddess,
+for we give them to you in preference to all the gods in Olympus:
+therefore speed us still further towards the horses and
+sleeping-ground of the Thracians."
+</para>
+
+<para>
+With these words he took the spoils and set them upon a tamarisk
+tree, and they marked the place by pulling up reeds and gathering
+boughs of tamarisk that they might not miss it as they came back
+through the' flying hours of darkness. The two then went onwards
+amid the fallen armour and the blood, and came presently to the
+company of Thracian soldiers, who were sleeping, tired out with
+their day's toil; their goodly armour was lying on the ground
+beside them all orderly in three rows, and each man had his yoke
+of horses beside him. Rhesus was sleeping in the middle, and hard
+by him his horses were made fast to the topmost rim of his
+chariot. Ulysses from some way off saw him and said, "This,
+Diomed, is the man, and these are the horses about which Dolon
+whom we killed told us. Do your very utmost; dally not about your
+armour, but loose the horses at once--or else kill the men
+yourself, while I see to the horses."
+</para>
+
+<para>
+Thereon Minerva put courage into the heart of Diomed, and he
+smote them right and left. They made a hideous groaning as they
+were being hacked about, and the earth was red with their blood.
+As a lion springs furiously upon a flock of sheep or goats when
+he finds without their shepherd, so did the son of Tydeus set
+upon the Thracian soldiers till he had killed twelve. As he
+killed them Ulysses came and drew them aside by their feet one by
+one, that the horses might go forward freely without being
+frightened as they passed over the dead bodies, for they were not
+yet used to them. When the son of Tydeus came to the king, he
+killed him too (which made thirteen), as he was breathing hard,
+for by the counsel of Minerva an evil dream, the seed of Oeneus,
+hovered that night over his head. Meanwhile Ulysses untied the
+horses, made them fast one to another and drove them off,
+striking them with his bow, for he had forgotten to take the whip
+from the chariot. Then he whistled as a sign to Diomed.
+</para>
+
+<para>
+But Diomed stayed where he was, thinking what other daring deed
+he might accomplish. He was doubting whether to take the chariot
+in which the king's armour was lying, and draw it out by the
+pole, or to lift the armour out and carry it off; or whether
+again, he should not kill some more Thracians. While he was thus
+hesitating Minerva came up to him and said, "Get back, Diomed, to
+the ships or you may be driven thither, should some other god
+rouse the Trojans."
+</para>
+
+<para>
+Diomed knew that it was the goddess, and at once sprang upon the
+horses. Ulysses beat them with his bow and they flew onward to
+the ships of the Achaeans.
+</para>
+
+<para>
+But Apollo kept no blind look-out when he saw Minerva with the
+son of Tydeus. He was angry with her, and coming to the host of
+the Trojans he roused Hippocoon, a counsellor of the Thracians
+and a noble kinsman of Rhesus. He started up out of his sleep and
+saw that the horses were no longer in their place, and that the
+men were gasping in their death-agony; on this he groaned aloud,
+and called upon his friend by name. Then the whole Trojan camp
+was in an uproar as the people kept hurrying together, and they
+marvelled at the deeds of the heroes who had now got away towards
+the ships.
+</para>
+
+<para>
+When they reached the place where they had killed Hector's scout,
+Ulysses stayed his horses, and the son of Tydeus, leaping to the
+ground, placed the blood-stained spoils in the hands of Ulysses
+and remounted: then he lashed the horses onwards, and they flew
+forward nothing loth towards the ships as though of their own
+free will. Nestor was first to hear the tramp of their feet. "My
+friends," said he, "princes and counsellors of the Argives, shall
+I guess right or wrong?--but I must say what I think: there is a
+sound in my ears as of the tramp of horses. I hope it may Diomed
+and Ulysses driving in horses from the Trojans, but I much fear
+that the bravest of the Argives may have come to some harm at
+their hands."
+</para>
+
+<para>
+He had hardly done speaking when the two men came in and
+dismounted, whereon the others shook hands right gladly with them
+and congratulated them. Nestor knight of Gerene was first to
+question them. "Tell me," said he, "renowned Ulysses, how did you
+two come by these horses? Did you steal in among the Trojan
+forces, or did some god meet you and give them to you? They are
+like sunbeams. I am well conversant with the Trojans, for old
+warrior though I am I never hold back by the ships, but I never
+yet saw or heard of such horses as these are. Surely some god
+must have met you and given them to you, for you are both of you
+dear to Jove, and to Jove's daughter Minerva."
+</para>
+
+<para>
+And Ulysses answered, "Nestor son of Neleus, honour to the
+Achaean name, heaven, if it so will, can give us even better
+horses than these, for the gods are far mightier than we are.
+These horses, however, about which you ask me, are freshly come
+from Thrace. Diomed killed their king with the twelve bravest of
+his companions. Hard by the ships we took a thirteenth man--a
+scout whom Hector and the other Trojans had sent as a spy upon
+our ships."
+</para>
+
+<para>
+He laughed as he spoke and drove the horses over the ditch, while
+the other Achaeans followed him gladly. When they reached the
+strongly built quarters of the son of Tydeus, they tied the
+horses with thongs of leather to the manger, where the steeds of
+Diomed stood eating their sweet corn, but Ulysses hung the
+blood-stained spoils of Dolon at the stern of his ship, that they
+might prepare a sacred offering to Minerva. As for themselves,
+they went into the sea and washed the sweat from their bodies,
+and from their necks and thighs. When the sea-water had taken all
+the sweat from off them, and had refreshed them, they went into
+the baths and washed themselves. After they had so done and had
+anointed themselves with oil, they sat down to table, and drawing
+from a full mixing-bowl, made a drink-offering of wine to
+Minerva.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK XI</title>
+
+<para>
+AND now as Dawn rose from her couch beside Tithonus, harbinger of
+light alike to mortals and immortals, Jove sent fierce Discord
+with the ensign of war in her hands to the ships of the Achaeans.
+She took her stand by the huge black hull of Ulysses' ship which
+was middlemost of all, so that her voice might carry farthest on
+either side, on the one hand towards the tents of Ajax son of
+Telamon, and on the other towards those of Achilles--for these
+two heroes, well-assured of their own strength, had valorously
+drawn up their ships at the two ends of the line. There she took
+her stand, and raised a cry both loud and shrill that filled the
+Achaeans with courage, giving them heart to fight resolutely and
+with all their might, so that they had rather stay there and do
+battle than go home in their ships.
+</para>
+
+<para>
+The son of Atreus shouted aloud and bade the Argives gird
+themselves for battle while he put on his armour. First he girded
+his goodly greaves about his legs, making them fast with ankle-
+clasps of silver; and about his chest he set the breastplate
+which Cinyras had once given him as a guest-gift. It had been
+noised abroad as far as Cyprus that the Achaeans were about to
+sail for Troy, and therefore he gave it to the king. It had ten
+courses of dark cyanus, twelve of gold, and ten of tin. There
+were serpents of cyanus that reared themselves up towards the
+neck, three upon either side, like the rainbows which the son of
+Saturn has set in heaven as a sign to mortal men. About his
+shoulders he threw his sword, studded with bosses of gold; and
+the scabbard was of silver with a chain of gold wherewith to hang
+it. He took moreover the richly-dight shield that covered his
+body when he was in battle--fair to see, with ten circles of
+bronze running all round it. On the body of the shield there were
+twenty bosses of white tin, with another of dark cyanus in the
+middle: this last was made to show a Gorgon's head, fierce and
+grim, with Rout and Panic on either side. The band for the arm to
+go through was of silver, on which there was a writhing snake of
+cyanus with three heads that sprang from a single neck, and went
+in and out among one another. On his head Agamemnon set a helmet,
+with a peak before and behind, and four plumes of horse-hair that
+nodded menacingly above it; then he grasped two redoubtable
+bronze-shod spears, and the gleam of his armour shot from him as
+a flame into the firmament, while Juno and Minerva thundered in
+honour of the king of rich Mycene.
+</para>
+
+<para>
+Every man now left his horses in charge of his charioteer to hold
+them in readiness by the trench, while he went into battle on
+foot clad in full armour, and a mighty uproar rose on high into
+the dawning. The chiefs were armed and at the trench before the
+horses got there, but these came up presently. The son of Saturn
+sent a portent of evil sound about their host, and the dew fell
+red with blood, for he was about to send many a brave man
+hurrying down to Hades.
+</para>
+
+<para>
+The Trojans, on the other side upon the rising slope of the
+plain, were gathered round great Hector, noble Polydamas, Aeneas
+who was honoured by the Trojans like an immortal, and the three
+sons of Antenor, Polybus, Agenor, and young Acamas beauteous as a
+god. Hector's round shield showed in the front rank, and as some
+baneful star that shines for a moment through a rent in the
+clouds and is again hidden beneath them; even so was Hector now
+seen in the front ranks and now again in the hindermost, and his
+bronze armour gleamed like the lightning of aegis-bearing Jove.
+</para>
+
+<para>
+And now as a band of reapers mow swathes of wheat or barley upon
+a rich man's land, and the sheaves fall thick before them, even
+so did the Trojans and Achaeans fall upon one another; they were
+in no mood for yielding but fought like wolves, and neither side
+got the better of the other. Discord was glad as she beheld them,
+for she was the only god that went among them; the others were
+not there, but stayed quietly each in his own home among the
+dells and valleys of Olympus. All of them blamed the son of
+Saturn for wanting to give victory to the Trojans, but father
+Jove heeded them not: he held aloof from all, and sat apart in
+his all-glorious majesty, looking down upon the city of the
+Trojans, the ships of the Achaeans, the gleam of bronze, and
+alike upon the slayers and on the slain.
+</para>
+
+<para>
+Now so long as the day waxed and it was still morning, their
+darts rained thick on one another and the people perished, but as
+the hour drew nigh when a woodman working in some mountain forest
+will get his midday meal--for he has felled till his hands are
+weary; he is tired out, and must now have food--then the Danaans
+with a cry that rang through all their ranks, broke the
+battalions of the enemy. Agamemnon led them on, and slew first
+Bienor, a leader of his people, and afterwards his comrade and
+charioteer Oileus, who sprang from his chariot and was coming
+full towards him; but Agamemnon struck him on the forehead with
+his spear; his bronze visor was of no avail against the weapon,
+which pierced both bronze and bone, so that his brains were
+battered in and he was killed in full fight.
+</para>
+
+<para>
+Agamemnon stripped their shirts from off them and left them with
+their breasts all bare to lie where they had fallen. He then went
+on to kill Isus and Antiphus two sons of Priam, the one a
+bastard, the other born in wedlock; they were in the same
+chariot--the bastard driving, while noble Antiphus fought beside
+him. Achilles had once taken both of them prisoners in the glades
+of Ida, and had bound them with fresh withes as they were
+shepherding, but he had taken a ransom for them; now, however,
+Agamemnon son of Atreus smote Isus in the chest above the nipple
+with his spear, while he struck Antiphus hard by the ear and
+threw him from his chariot. Forthwith he stripped their goodly
+armour from off them and recognized them, for he had already seen
+them at ships when Achilles brought them in from Ida. As a lion
+fastens on the fawns of a hind and crushes them in his great
+jaws, robbing them of their tender life while he on his way back
+to his lair--the hind can do nothing for them even though she be
+close by, for she is in an agony of fear, and flies through the
+thick forest, sweating, and at her utmost speed before the mighty
+monster--so, no man of the Trojans could help Isus and Antiphus,
+for they were themselves flying panic before the Argives.
+</para>
+
+<para>
+Then King Agamemnon took the two sons of Antimachus, Pisander and
+brave Hippolochus. It was Antimachus who had been foremost in
+preventing Helen's being restored to Menelaus, for he was largely
+bribed by Alexandrus; and now Agamemnon took his two sons, both
+in the same chariot, trying to bring their horses to a stand--for
+they had lost hold of the reins and the horses were mad with
+fear. The son of Atreus sprang upon them like a lion, and the
+pair besought him from their chariot. "Take us alive," they
+cried, "son of Atreus, and you shall receive a great ransom for
+us. Our father Antimachus has great store of gold, bronze, and
+wrought iron, and from this he will satisfy you with a very large
+ransom should he hear of our being alive at the ships of the
+Achaeans."
+</para>
+
+<para>
+With such piteous words and tears did they beseech the king, but
+they heard no pitiful answer in return. "If," said Agamemnon,
+"you are sons of Antimachus, who once at a council of Trojans
+proposed that Menelaus and Ulysses, who had come to you as
+envoys, should be killed and not suffered to return, you shall
+now pay for the foul iniquity of your father."
+</para>
+
+<para>
+As he spoke he felled Pisander from his chariot to the earth,
+smiting him on the chest with his spear, so that he lay face
+uppermost upon the ground. Hippolochus fled, but him too did
+Agamemnon smite; he cut off his hands and his head--which he sent
+rolling in among the crowd as though it were a ball. There he let
+them both lie, and wherever the ranks were thickest thither he
+flew, while the other Achaeans followed. Foot soldiers drove the
+foot soldiers of the foe in rout before them, and slew them;
+horsemen did the like by horsemen, and the thundering tramp of
+the horses raised a cloud of dust from off the plain. King
+Agamemnon followed after, ever slaying them and cheering on the
+Achaeans. As when some mighty forest is all ablaze--the eddying
+gusts whirl fire in all directions till the thickets shrivel and
+are consumed before the blast of the flame--even so fell the
+heads of the flying Trojans before Agamemnon son of Atreus, and
+many a noble pair of steeds drew an empty chariot along the
+highways of war, for lack of drivers who were lying on the plain,
+more useful now to vultures than to their wives.
+</para>
+
+<para>
+Jove drew Hector away from the darts and dust, with the carnage
+and din of battle; but the son of Atreus sped onwards, calling
+out lustily to the Danaans. They flew on by the tomb of old Ilus,
+son of Dardanus, in the middle of the plain, and past the place
+of the wild fig-tree making always for the city--the son of
+Atreus still shouting, and with hands all bedrabbled in gore; but
+when they had reached the Scaean gates and the oak tree, there
+they halted and waited for the others to come up. Meanwhile the
+Trojans kept on flying over the middle of the plain like a herd
+of cows maddened with fright when a lion has attacked them in the
+dead of night--he springs on one of them, seizes her neck in the
+grip of his strong teeth and then laps up her blood and gorges
+himself upon her entrails--even so did King Agamemnon son of
+Atreus pursue the foe, ever slaughtering the hindmost as they
+fled pell-mell before him. Many a man was flung headlong from his
+chariot by the hand of the son of Atreus, for he wielded his
+spear with fury.
+</para>
+
+<para>
+But when he was just about to reach the high wall and the city,
+the father of gods and men came down from heaven and took his
+seat, thunderbolt in hand, upon the crest of many-fountained Ida.
+He then told Iris of the golden wings to carry a message for him.
+"Go," said he, "fleet Iris, and speak thus to Hector--say that so
+long as he sees Agamemnon heading his men and making havoc of the
+Trojan ranks, he is to keep aloof and bid the others bear the
+brunt of the battle, but when Agamemnon is wounded either by
+spear or arrow, and takes to his chariot, then will I vouchsafe
+him strength to slay till he reach the ships and night falls at
+the going down of the sun."
+</para>
+
+<para>
+Iris hearkened and obeyed. Down she went to strong Ilius from the
+crests of Ida, and found Hector son of Priam standing by his
+chariot and horses. Then she said, "Hector son of Priam, peer of
+gods in counsel, father Jove has sent me to bear you this
+message--so long as you see Agamemnon heading his men and making
+havoc of the Trojan ranks, you are to keep aloof and bid the
+others bear the brunt of the battle, but when Agamemnon is
+wounded either by spear or arrow, and takes to his chariot, then
+will Jove vouchsafe you strength to slay till you reach the
+ships, and till night falls at the going down of the sun."
+</para>
+
+<para>
+When she had thus spoken Iris left him, and Hector sprang full
+armed from his chariot to the ground, brandishing his spear as he
+went about everywhere among the host, cheering his men on to
+fight, and stirring the dread strife of battle. The Trojans then
+wheeled round, and again met the Achaeans, while the Argives on
+their part strengthened their battalions. The battle was now in
+array and they stood face to face with one another, Agamemnon
+ever pressing forward in his eagerness to be ahead of all others.
+</para>
+
+<para>
+Tell me now ye Muses that dwell in the mansions of Olympus, who,
+whether of the Trojans or of their allies, was first to face
+Agamemnon? It was Iphidamas son of Antenor, a man both brave and
+of great stature, who was brought up in fertile Thrace, the
+mother of sheep. Cisses, his mother's father, brought him up in
+his own house when he was a child--Cisses, father to fair Theano.
+When he reached manhood, Cisses would have kept him there, and
+was for giving him his daughter in marriage, but as soon as he
+had married he set out to fight the Achaeans with twelve ships
+that followed him: these he had left at Percote and had come on
+by land to Ilius. He it was that now met Agamemnon son of Atreus.
+When they were close up with one another, the son of Atreus
+missed his aim, and Iphidamas hit him on the girdle below the
+cuirass and then flung himself upon him, trusting to his strength
+of arm; the girdle, however, was not pierced, nor nearly so, for
+the point of the spear struck against the silver and was turned
+aside as though it had been lead: King Agamemnon caught it from
+his hand, and drew it towards him with the fury of a lion; he
+then drew his sword, and killed Iphidamas by striking him on the
+neck. So there the poor fellow lay, sleeping a sleep as it were
+of bronze, killed in the defence of his fellow-citizens, far from
+his wedded wife, of whom he had had no joy though he had given
+much for her: he had given a hundred-head of cattle down, and had
+promised later on to give a thousand sheep and goats mixed, from
+the countless flocks of which he was possessed. Agamemnon son of
+Atreus then despoiled him, and carried off his armour into the
+host of the Achaeans.
+</para>
+
+<para>
+When noble Coon, Antenor's eldest son, saw this, sore indeed were
+his eyes at the sight of his fallen brother. Unseen by Agamemnon
+he got beside him, spear in hand, and wounded him in the middle
+of his arm below the elbow, the point of the spear going right
+through the arm. Agamemnon was convulsed with pain, but still not
+even for this did he leave off struggling and fighting, but
+grasped his spear that flew as fleet as the wind, and sprang upon
+Coon who was trying to drag off the body of his brother--his
+father's son--by the foot, and was crying for help to all the
+bravest of his comrades; but Agamemnon struck him with a
+bronze-shod spear and killed him as he was dragging the dead body
+through the press of men under cover of his shield: he then cut
+off his head, standing over the body of Iphidamas. Thus did the
+sons of Antenor meet their fate at the hands of the son of
+Atreus, and go down into the house of Hades.
+</para>
+
+<para>
+As long as the blood still welled warm from his wound Agamemnon
+went about attacking the ranks of the enemy with spear and sword
+and with great handfuls of stone, but when the blood had ceased
+to flow and the wound grew dry, the pain became great. As the
+sharp pangs which the Eilithuiae, goddesses of childbirth,
+daughters of Juno and dispensers of cruel pain, send upon a woman
+when she is in labour--even so sharp were the pangs of the son of
+Atreus. He sprang on to his chariot, and bade his charioteer
+drive to the ships, for he was in great agony. With a loud clear
+voice he shouted to the Danaans, "My friends, princes and
+counsellors of the Argives, defend the ships yourselves, for Jove
+has not suffered me to fight the whole day through against the
+Trojans."
+</para>
+
+<para>
+With this the charioteer turned his horses towards the ships, and
+they flew forward nothing loth. Their chests were white with foam
+and their bellies with dust, as they drew the wounded king out of
+the battle.
+</para>
+
+<para>
+When Hector saw Agamemnon quit the field, he shouted to the
+Trojans and Lycians saying, "Trojans, Lycians, and Dardanian
+warriors, be men, my friends, and acquit yourselves in battle
+bravely; their best man has left them, and Jove has vouchsafed me
+a great triumph; charge the foe with your chariots that you may
+win still greater glory."
+</para>
+
+<para>
+With these words he put heart and soul into them all, and as a
+huntsman hounds his dogs on against a lion or wild boar, even so
+did Hector, peer of Mars, hound the proud Trojans on against the
+Achaeans. Full of hope he plunged in among the foremost, and fell
+on the fight like some fierce tempest that swoops down upon the
+sea, and lashes its deep blue waters into fury.
+</para>
+
+<para>
+What, then is the full tale of those whom Hector son of Priam
+killed in the hour of triumph which Jove then vouchsafed him?
+First Asaeus, Autonous, and Opites; Dolops son of Clytius,
+Opheltius and Agelaus; Aesymnus, Orus and Hipponous steadfast in
+battle; these chieftains of the Achaeans did Hector slay, and
+then he fell upon the rank and file. As when the west wind
+hustles the clouds of the white south and beats them down with
+the fierceness of its fury--the waves of the sea roll high, and
+the spray is flung aloft in the rage of the wandering wind--even
+so thick were the heads of them that fell by the hand of Hector.
+</para>
+
+<para>
+All had then been lost and no help for it, and the Achaeans would
+have fled pell-mell to their ships, had not Ulysses cried out to
+Diomed, "Son of Tydeus, what has happened to us that we thus
+forget our prowess? Come, my good fellow, stand by my side and
+help me, we shall be shamed for ever if Hector takes the ships."
+</para>
+
+<para>
+And Diomed answered, "Come what may, I will stand firm; but we
+shall have scant joy of it, for Jove is minded to give victory to
+the Trojans rather than to us."
+</para>
+
+<para>
+With these words he struck Thymbraeus from his chariot to the
+ground, smiting him in the left breast with his spear, while
+Ulysses killed Molion who was his squire. These they let lie, now
+that they had stopped their fighting; the two heroes then went on
+playing havoc with the foe, like two wild boars that turn in fury
+and rend the hounds that hunt them. Thus did they turn upon the
+Trojans and slay them, and the Achaeans were thankful to have
+breathing time in their flight from Hector.
+</para>
+
+<para>
+They then took two princes with their chariot, the two sons of
+Merops of Percote, who excelled all others in the arts of
+divination. He had forbidden his sons to go to the war, but they
+would not obey him, for fate lured them to their fall. Diomed son
+of Tydeus slew them both and stripped them of their armour, while
+Ulysses killed Hippodamus and Hypeirochus.
+</para>
+
+<para>
+And now the son of Saturn as he looked down from Ida ordained
+that neither side should have the advantage, and they kept on
+killing one another. The son of Tydeus speared Agastrophus son of
+Paeon in the hip-joint with his spear. His chariot was not at
+hand for him to fly with, so blindly confident had he been. His
+squire was in charge of it at some distance and he was fighting
+on foot among the foremost until he lost his life. Hector soon
+marked the havoc Diomed and Ulysses were making, and bore down
+upon them with a loud cry, followed by the Trojan ranks; brave
+Diomed was dismayed when he saw them, and said to Ulysses who was
+beside him, "Great Hector is bearing down upon us and we shall be
+undone; let us stand firm and wait his onset."
+</para>
+
+<para>
+He poised his spear as he spoke and hurled it, nor did he miss
+his mark. He had aimed at Hector's head near the top of his
+helmet, but bronze was turned by bronze, and Hector was
+untouched, for the spear was stayed by the visored helm made with
+three plates of metal, which Phoebus Apollo had given him. Hector
+sprang back with a great bound under cover of the ranks; he fell
+on his knees and propped himself with his brawny hand leaning on
+the ground, for darkness had fallen on his eyes. The son of
+Tydeus having thrown his spear dashed in among the foremost
+fighters, to the place where he had seen it strike the ground;
+meanwhile Hector recovered himself and springing back into his
+chariot mingled with the crowd, by which means he saved his life.
+But Diomed made at him with his spear and said, "Dog, you have
+again got away though death was close on your heels. Phoebus
+Apollo, to whom I ween you pray ere you go into battle, has again
+saved you, nevertheless I will meet you and make an end of you
+hereafter, if there is any god who will stand by me too and be my
+helper. For the present I must pursue those I can lay hands on."
+</para>
+
+<para>
+As he spoke he began stripping the spoils from the son of Paeon,
+but Alexandrus husband of lovely Helen aimed an arrow at him,
+leaning against a pillar of the monument which men had raised to
+Ilus son of Dardanus, a ruler in days of old. Diomed had taken
+the cuirass from off the breast of Agastrophus, his heavy helmet
+also, and the shield from off his shoulders, when Paris drew his
+bow and let fly an arrow that sped not from his hand in vain, but
+pierced the flat of Diomed's right foot, going right through it
+and fixing itself in the ground. Thereon Paris with a hearty
+laugh sprang forward from his hiding-place, and taunted him
+saying, "You are wounded--my arrow has not been shot in vain;
+would that it had hit you in the belly and killed you, for thus
+the Trojans, who fear you as goats fear a lion, would have had a
+truce from evil."
+</para>
+
+<para>
+Diomed all undaunted answered, "Archer, you who without your bow
+are nothing, slanderer and seducer, if you were to be tried in
+single combat fighting in full armour, your bow and your arrows
+would serve you in little stead. Vain is your boast in that you
+have scratched the sole of my foot. I care no more than if a girl
+or some silly boy had hit me. A worthless coward can inflict but
+a light wound; when I wound a man though I but graze his skin it
+is another matter, for my weapon will lay him low. His wife will
+tear her cheeks for grief and his children will be fatherless:
+there will he rot, reddening the earth with his blood, and
+vultures, not women, will gather round him."
+</para>
+
+<para>
+Thus he spoke, but Ulysses came up and stood over him. Under this
+cover he sat down to draw the arrow from his foot, and sharp was
+the pain he suffered as he did so. Then he sprang on to his
+chariot and bade the charioteer drive him to the ships, for he
+was sick at heart.
+</para>
+
+<para>
+Ulysses was now alone; not one of the Argives stood by him, for
+they were all panic-stricken. "Alas," said he to himself in his
+dismay, "what will become of me? It is ill if I turn and fly
+before these odds, but it will be worse if I am left alone and
+taken prisoner, for the son of Saturn has struck the rest of the
+Danaans with panic. But why talk to myself in this way? Well do I
+know that though cowards quit the field, a hero, whether he wound
+or be wounded, must stand firm and hold his own."
+</para>
+
+<para>
+While he was thus in two minds, the ranks of the Trojans advanced
+and hemmed him in, and bitterly did they come to rue it. As
+hounds and lusty youths set upon a wild boar that sallies from
+his lair whetting his white tusks--they attack him from every
+side and can hear the gnashing of his jaws, but for all his
+fierceness they still hold their ground--even so furiously did
+the Trojans attack Ulysses. First he sprang spear in hand upon
+Deiopites and wounded him on the shoulder with a downward blow;
+then he killed Thoon and Ennomus. After these he struck
+Chersidamas in the loins under his shield as he had just sprung
+down from his chariot; so he fell in the dust and clutched the
+earth in the hollow of his hand. These he let lie, and went on to
+wound Charops son of Hippasus own brother to noble Socus. Socus,
+hero that he was, made all speed to help him, and when he was
+close to Ulysses he said, "Far-famed Ulysses, insatiable of craft
+and toil, this day you shall either boast of having killed both
+the sons of Hippasus and stripped them of their armour, or you
+shall fall before my spear."
+</para>
+
+<para>
+With these words he struck the shield of Ulysses. The spear went
+through the shield and passed on through his richly wrought
+cuirass, tearing the flesh from his side, but Pallas Minerva did
+not suffer it to pierce the entrails of the hero. Ulysses knew
+that his hour was not yet come, but he gave ground and said to
+Socus, "Wretch, you shall now surely die. You have stayed me from
+fighting further with the Trojans, but you shall now fall by my
+spear, yielding glory to myself, and your soul to Hades of the
+noble steeds."
+</para>
+
+<para>
+Socus had turned in flight, but as he did so, the spear struck
+him in the back midway between the shoulders, and went right
+through his chest. He fell heavily to the ground and Ulysses
+vaunted over him saying, "O Socus, son of Hippasus tamer of
+horses, death has been too quick for you and you have not escaped
+him: poor wretch, not even in death shall your father and mother
+close your eyes, but the ravening vultures shall enshroud you
+with the flapping of their dark wings and devour you. Whereas
+even though I fall the Achaeans will give me my due rites of
+burial."
+</para>
+
+<para>
+So saying he drew Socus's heavy spear out of his flesh and from
+his shield, and the blood welled forth when the spear was
+withdrawn so that he was much dismayed. When the Trojans saw that
+Ulysses was bleeding they raised a great shout and came on in a
+body towards him; he therefore gave ground, and called his
+comrades to come and help him. Thrice did he cry as loudly as man
+can cry, and thrice did brave Menelaus hear him; he turned,
+therefore, to Ajax who was close beside him and said, "Ajax,
+noble son of Telamon, captain of your people, the cry of Ulysses
+rings in my ears, as though the Trojans had cut him off and were
+worsting him while he is single-handed. Let us make our way
+through the throng; it will be well that we defend him; I fear he
+may come to harm for all his valour if he be left without
+support, and the Danaans would miss him sorely."
+</para>
+
+<para>
+He led the way and mighty Ajax went with him. The Trojans had
+gathered round Ulysses like ravenous mountain jackals round the
+carcase of some horned stag that has been hit with an arrow--the
+stag has fled at full speed so long as his blood was warm and his
+strength has lasted, but when the arrow has overcome him, the
+savage jackals devour him in the shady glades of the forest. Then
+heaven sends a fierce lion thither, whereon the jackals fly in
+terror and the lion robs them of their prey--even so did Trojans
+many and brave gather round crafty Ulysses, but the hero stood at
+bay and kept them off with his spear. Ajax then came up with his
+shield before him like a wall, and stood hard by, whereon the
+Trojans fled in all directions. Menelaus took Ulysses by the
+hand, and led him out of the press while his squire brought up
+his chariot, but Ajax rushed furiously on the Trojans and killed
+Doryclus, a bastard son of Priam; then he wounded Pandocus,
+Lysandrus, Pyrasus, and Pylartes; as some swollen torrent comes
+rushing in full flood from the mountains on to the plain, big
+with the rain of heaven--many a dry oak and many a pine does it
+engulf, and much mud does it bring down and cast into the sea--
+even so did brave Ajax chase the foe furiously over the plain,
+slaying both men and horses.
+</para>
+
+<para>
+Hector did not yet know what Ajax was doing, for he was fighting
+on the extreme left of the battle by the banks of the river
+Scamander, where the carnage was thickest and the war-cry loudest
+round Nestor and brave Idomeneus. Among these Hector was making
+great slaughter with his spear and furious driving, and was
+destroying the ranks that were opposed to him; still the Achaeans
+would have given no ground, had not Alexandrus husband of lovely
+Helen stayed the prowess of Machaon, shepherd of his people, by
+wounding him in the right shoulder with a triple-barbed arrow.
+The Achaeans were in great fear that as the fight had turned
+against them the Trojans might take him prisoner, and Idomeneus
+said to Nestor, "Nestor son of Neleus, honour to the Achaean
+name, mount your chariot at once; take Machaon with you and drive
+your horses to the ships as fast as you can. A physician is worth
+more than several other men put together, for he can cut out
+arrows and spread healing herbs."
+</para>
+
+<para>
+Nestor knight of Gerene did as Idomeneus had counselled; he at
+once mounted his chariot, and Machaon son of the famed physician
+Aesculapius, went with him. He lashed his horses and they flew
+onward nothing loth towards the ships, as though of their own
+free will.
+</para>
+
+<para>
+Then Cebriones seeing the Trojans in confusion said to Hector
+from his place beside him, "Hector, here are we two fighting on
+the extreme wing of the battle, while the other Trojans are in
+pell-mell rout, they and their horses. Ajax son of Telamon is
+driving them before him; I know him by the breadth of his shield:
+let us turn our chariot and horses thither, where horse and foot
+are fighting most desperately, and where the cry of battle is
+loudest."
+</para>
+
+<para>
+With this he lashed his goodly steeds, and when they felt the
+whip they drew the chariot full speed among the Achaeans and
+Trojans, over the bodies and shields of those that had fallen:
+the axle was bespattered with blood, and the rail round the car
+was covered with splashes both from the horses' hoofs and from
+the tyres of the wheels. Hector tore his way through and flung
+himself into the thick of the fight, and his presence threw the
+Danaans into confusion, for his spear was not long idle;
+nevertheless though he went among the ranks with sword and spear,
+and throwing great stones, he avoided Ajax son of Telamon, for
+Jove would have been angry with him if he had fought a better man
+than himself.
+</para>
+
+<para>
+Then father Jove from his high throne struck fear into the heart
+of Ajax, so that he stood there dazed and threw his shield behind
+him--looking fearfully at the throng of his foes as though he
+were some wild beast, and turning hither and thither but
+crouching slowly backwards. As peasants with their hounds chase a
+lion from their stockyard, and watch by night to prevent his
+carrying off the pick of their herd--he makes his greedy spring,
+but in vain, for the darts from many a strong hand fall thick
+around him, with burning brands that scare him for all his fury,
+and when morning comes he slinks foiled and angry away--even so
+did Ajax, sorely against his will, retreat angrily before the
+Trojans, fearing for the ships of the Achaeans. Or as some lazy
+ass that has had many a cudgel broken about his back, when he
+into a field begins eating the corn--boys beat him but he is too
+many for them, and though they lay about with their sticks they
+cannot hurt him; still when he has had his fill they at last
+drive him from the field--even so did the Trojans and their
+allies pursue great Ajax, ever smiting the middle of his shield
+with their darts. Now and again he would turn and show fight,
+keeping back the battalions of the Trojans, and then he would
+again retreat; but he prevented any of them from making his way
+to the ships. Single-handed he stood midway between the Trojans
+and Achaeans: the spears that sped from their hands stuck some of
+them in his mighty shield, while many, though thirsting for his
+blood, fell to the ground ere they could reach him to the
+wounding of his fair flesh.
+</para>
+
+<para>
+Now when Eurypylus the brave son of Euaemon saw that Ajax was
+being overpowered by the rain of arrows, he went up to him and
+hurled his spear. He struck Apisaon son of Phausius in the liver
+below the midriff, and laid him low. Eurypylus sprang upon him,
+and stripped the armour from his shoulders; but when Alexandrus
+saw him, he aimed an arrow at him which struck him in the right
+thigh; the arrow broke, but the point that was left in the wound
+dragged on the thigh; he drew back, therefore, under cover of his
+comrades to save his life, shouting as he did so to the Danaans,
+"My friends, princes and counsellors of the Argives, rally to the
+defence of Ajax who is being overpowered, and I doubt whether he
+will come out of the fight alive. Hither, then, to the rescue of
+great Ajax son of Telamon."
+</para>
+
+<para>
+Even so did he cry when he was wounded; thereon the others came
+near, and gathered round him, holding their shields upwards from
+their shoulders so as to give him cover. Ajax then made towards
+them, and turned round to stand at bay as soon as he had reached
+his men.
+</para>
+
+<para>
+Thus then did they fight as it were a flaming fire. Meanwhile the
+mares of Neleus, all in a lather with sweat, were bearing Nestor
+out of the fight, and with him Machaon shepherd of his people.
+Achilles saw and took note, for he was standing on the stern of
+his ship watching the hard stress and struggle of the fight. He
+called from the ship to his comrade Patroclus, who heard him in
+the tent and came out looking like Mars himself--here indeed was
+the beginning of the ill that presently befell him. "Why," said
+he, "Achilles, do you call me? What do you want with me?" And
+Achilles answered, "Noble son of Menoetius, man after my own
+heart, I take it that I shall now have the Achaeans praying at my
+knees, for they are in great straits; go, Patroclus, and ask
+Nestor who it is that he is bearing away wounded from the field;
+from his back I should say it was Machaon son of Aesculapius, but
+I could not see his face for the horses went by me at full
+speed."
+</para>
+
+<para>
+Patroclus did as his dear comrade had bidden him, and set off
+running by the ships and tents of the Achaeans.
+</para>
+
+<para>
+When Nestor and Machaon had reached the tents of the son of
+Neleus, they dismounted, and an esquire, Eurymedon, took the
+horses from the chariot. The pair then stood in the breeze by the
+seaside to dry the sweat from their shirts, and when they had so
+done they came inside and took their seats. Fair Hecamede, whom
+Nestor had had awarded to him from Tenedos when Achilles took it,
+mixed them a mess; she was daughter of wise Arsinous, and the
+Achaeans had given her to Nestor because he excelled all of them
+in counsel. First she set for them a fair and well-made table
+that had feet of cyanus; on it there was a vessel of bronze and
+an onion to give relish to the drink, with honey and cakes of
+barley-meal. There was also a cup of rare workmanship which the
+old man had brought with him from home, studded with bosses of
+gold; it had four handles, on each of which there were two golden
+doves feeding, and it had two feet to stand on. Any one else
+would hardly have been able to lift it from the table when it was
+full, but Nestor could do so quite easily. In this the woman, as
+fair as a goddess, mixed them a mess with Pramnian wine; she
+grated goat's milk cheese into it with a bronze grater, threw in
+a handful of white barley-meal, and having thus prepared the mess
+she bade them drink it. When they had done so and had thus
+quenched their thirst, they fell talking with one another, and at
+this moment Patroclus appeared at the door.
+</para>
+
+<para>
+When the old man saw him he sprang from his seat, seized his
+hand, led him into the tent, and bade him take his place among
+them; but Patroclus stood where he was and said, "Noble sir, I
+may not stay, you cannot persuade me to come in; he that sent me
+is not one to be trifled with, and he bade me ask who the wounded
+man was whom you were bearing away from the field. I can now see
+for myself that he is Machaon, shepherd of his people. I must go
+back and tell Achilles. You, sir, know what a terrible man he is,
+and how ready to blame even where no blame should lie."
+</para>
+
+<para>
+And Nestor answered, "Why should Achilles care to know how many
+of the Achaeans may be wounded? He recks not of the dismay that
+reigns in our host; our most valiant chieftains lie disabled,
+brave Diomed, son of Tydeus, is wounded; so are Ulysses and
+Agamemnon; Eurypylus has been hit with an arrow in the thigh, and
+I have just been bringing this man from the field--he too wounded
+with an arrow. Nevertheless, Achilles, so valiant though he be,
+cares not and knows no ruth. Will he wait till the ships, do what
+we may, are in a blaze, and we perish one upon the other? As for
+me, I have no strength nor stay in me any longer; would that I
+were still young and strong as in the days when there was a fight
+between us and the men of Elis about some cattle-raiding. I then
+killed Itymoneus, the valiant son of Hypeirochus, a dweller in
+Elis, as I was driving in the spoil; he was hit by a dart thrown
+by my hand while fighting in the front rank in defence of his
+cows, so he fell and the country people around him were in great
+fear. We drove off a vast quantity of booty from the plain, fifty
+herds of cattle and as many flocks of sheep; fifty droves also of
+pigs, and as many wide-spreading flocks of goats. Of horses,
+moreover, we seized a hundred and fifty, all of them mares, and
+many had foals running with them. All these did we drive by night
+to Pylus, the city of Neleus, taking them within the city; and
+the heart of Neleus was glad in that I had taken so much, though
+it was the first time I had ever been in the field. At daybreak
+the heralds went round crying that all in Elis to whom there was
+a debt owing should come; and the leading Pylians assembled to
+divide the spoils. There were many to whom the Epeans owed
+chattels, for we men of Pylus were few and had been oppressed
+with wrong; in former years Hercules had come, and had laid his
+hand heavy upon us, so that all our best men had perished. Neleus
+had had twelve sons, but I alone was left; the others had all
+been killed. The Epeans presuming upon all this had looked down
+upon us and had done us much evil. My father chose a herd of
+cattle and a great flock of sheep--three hundred in all--and he
+took their shepherds with him, for there was a great debt due to
+him in Elis, to wit four horses, winners of prizes. They and
+their chariots with them had gone to the games and were to run
+for a tripod, but King Augeas took them, and sent back their
+driver grieving for the loss of his horses. Neleus was angered by
+what he had both said and done, and took great value in return,
+but he divided the rest, that no man might have less than his
+full share.
+</para>
+
+<para>
+"Thus did we order all things, and offer sacrifices to the gods
+throughout the city; but three days afterwards the Epeans came in
+a body, many in number, they and their chariots, in full array,
+and with them the two Moliones in their armour, though they were
+still lads and unused to fighting. Now there is a certain town,
+Thryoessa, perched upon a rock on the river Alpheus, the border
+city Pylus. This they would destroy, and pitched their camp about
+it, but when they had crossed their whole plain, Minerva darted
+down by night from Olympus and bade us set ourselves in array;
+and she found willing soldiers in Pylos, for the men meant
+fighting. Neleus would not let me arm, and hid my horses, for he
+said that as yet I could know nothing about war; nevertheless
+Minerva so ordered the fight that, all on foot as I was, I fought
+among our mounted forces and vied with the foremost of them.
+There is a river Minyeius that falls into the sea near Arene, and
+there they that were mounted (and I with them) waited till
+morning, when the companies of foot soldiers came up with us in
+force. Thence in full panoply and equipment we came towards noon
+to the sacred waters of the Alpheus, and there we offered victims
+to almighty Jove, with a bull to Alpheus, another to Neptune, and
+a herd-heifer to Minerva. After this we took supper in our
+companies, and laid us down to rest each in his armour by the
+river.
+</para>
+
+<para>
+"The Epeans were beleaguering the city and were determined to
+take it, but ere this might be there was a desperate fight in
+store for them. When the sun's rays began to fall upon the earth
+we joined battle, praying to Jove and to Minerva, and when the
+fight had begun, I was the first to kill my man and take his
+horses--to wit the warrior Mulius. He was son-in-law to Augeas,
+having married his eldest daughter, golden-haired Agamede, who
+knew the virtues of every herb which grows upon the face of the
+earth. I speared him as he was coming towards me, and when he
+fell headlong in the dust, I sprang upon his chariot and took my
+place in the front ranks. The Epeans fled in all directions when
+they saw the captain of their horsemen (the best man they had)
+laid low, and I swept down on them like a whirlwind, taking fifty
+chariots--and in each of them two men bit the dust, slain by my
+spear. I should have even killed the two Moliones, sons of Actor,
+unless their real father, Neptune lord of the earthquake, had
+hidden them in a thick mist and borne them out of the fight.
+Thereon Jove vouchsafed the Pylians a great victory, for we
+chased them far over the plain, killing the men and bringing in
+their armour, till we had brought our horses to Buprasium, rich
+in wheat, and to the Olenian rock, with the hill that is called
+Alision, at which point Minerva turned the people back. There I
+slew the last man and left him; then the Achaeans drove their
+horses back from Buprasium to Pylos and gave thanks to Jove among
+the gods, and among mortal men to Nestor.
+</para>
+
+<para>
+"Such was I among my peers, as surely as ever was, but Achilles
+is for keeping all his valour for himself; bitterly will he rue
+it hereafter when the host is being cut to pieces. My good
+friend, did not Menoetius charge you thus, on the day when he
+sent you from Phthia to Agamemnon? Ulysses and I were in the
+house, inside, and heard all that he said to you; for we came to
+the fair house of Peleus while beating up recruits throughout all
+Achaea, and when we got there we found Menoetius and yourself,
+and Achilles with you. The old knight Peleus was in the outer
+court, roasting the fat thigh-bones of a heifer to Jove the lord
+of thunder; and he held a gold chalice in his hand from which he
+poured drink-offerings of wine over the burning sacrifice. You
+two were busy cutting up the heifer, and at that moment we stood
+at the gates, whereon Achilles sprang to his feet, led us by the
+hand into the house, placed us at table, and set before us such
+hospitable entertainment as guests expect. When we had satisfied
+ourselves with meat and drink, I said my say and urged both of
+you to join us. You were ready enough to do so, and the two old
+men charged you much and straitly. Old Peleus bade his son
+Achilles fight ever among the foremost and outvie his peers,
+while Menoetius the son of Actor spoke thus to you: 'My son,'
+said he, 'Achilles is of nobler birth than you are, but you are
+older than he, though he is far the better man of the two.
+Counsel him wisely, guide him in the right way, and he will
+follow you to his own profit.' Thus did your father charge you,
+but you have forgotten; nevertheless, even now, say all this to
+Achilles if he will listen to you. Who knows but with heaven's
+help you may talk him over, for it is good to take a friend's
+advice. If, however, he is fearful about some oracle, or if his
+mother has told him something from Jove, then let him send you,
+and let the rest of the Myrmidons follow with you, if perchance
+you may bring light and saving to the Danaans. And let him send
+you into battle clad in his own armour, that the Trojans may
+mistake you for him and leave off fighting; the sons of the
+Achaeans may thus have time to get their breath, for they are
+hard pressed and there is little breathing time in battle. You,
+who are fresh, might easily drive a tired enemy back to his walls
+and away from the tents and ships."
+</para>
+
+<para>
+With these words he moved the heart of Patroclus, who set off
+running by the line of the ships to Achilles, descendant of
+Aeacus. When he had got as far as the ships of Ulysses, where was
+their place of assembly and court of justice, with their altars
+dedicated to the gods, Eurypylus son of Euaemon, met him, wounded
+in the thigh with an arrow, and limping out of the fight. Sweat
+rained from his head and shoulders, and black blood welled from
+his cruel wound, but his mind did not wander. The son of
+Menoetius when he saw him had compassion upon him and spoke
+piteously saying, "O unhappy princes and counsellors of the
+Danaans, are you then doomed to feed the hounds of Troy with your
+fat, far from your friends and your native land? Say, noble
+Eurypylus, will the Achaeans be able to hold great Hector in
+check, or will they fall now before his spear?"
+</para>
+
+<para>
+Wounded Eurypylus made answer, "Noble Patroclus, there is no hope
+left for the Achaeans but they will perish at their ships. All
+they that were princes among us are lying struck down and wounded
+at the hands of the Trojans, who are waxing stronger and
+stronger. But save me and take me to your ship; cut out the arrow
+from my thigh; wash the black blood from off it with warm water,
+and lay upon it those gracious herbs which, so they say, have
+been shown you by Achilles, who was himself shown them by Chiron,
+most righteous of all the centaurs. For of the physicians
+Podalirius and Machaon, I hear that the one is lying wounded in
+his tent and is himself in need of healing, while the other is
+fighting the Trojans upon the plain."
+</para>
+
+<para>
+"Hero Eurypylus," replied the brave son of Menoetius, "how may
+these things be? What can I do? I am on my way to bear a message
+to noble Achilles from Nestor of Gerene, bulwark of the Achaeans,
+but even so I will not be unmindful of your distress."
+</para>
+
+<para>
+With this he clasped him round the middle and led him into the
+tent, and a servant, when he saw him, spread bullock-skins on the
+ground for him to lie on. He laid him at full length and cut out
+the sharp arrow from his thigh; he washed the black blood from
+the wound with warm water; he then crushed a bitter herb, rubbing
+it between his hands, and spread it upon the wound; this was a
+virtuous herb which killed all pain; so the wound presently dried
+and the blood left off flowing.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK XII</title>
+
+<para>
+SO THE son of Menoetius was attending to the hurt of Eurypylus
+within the tent, but the Argives and Trojans still fought
+desperately, nor were the trench and the high wall above it, to
+keep the Trojans in check longer. They had built it to protect
+their ships, and had dug the trench all round it that it might
+safeguard both the ships and the rich spoils which they had
+taken, but they had not offered hecatombs to the gods. It had
+been built without the consent of the immortals, and therefore it
+did not last. So long as Hector lived and Achilles nursed his
+anger, and so long as the city of Priam remained untaken, the
+great wall of the Achaeans stood firm; but when the bravest of
+the Trojans were no more, and many also of the Argives, though
+some were yet left alive--when, moreover, the city was sacked in
+the tenth year, and the Argives had gone back with their ships to
+their own country--then Neptune and Apollo took counsel to
+destroy the wall, and they turned on to it the streams of all the
+rivers from Mount Ida into the sea, Rhesus, Heptaporus, Caresus,
+Rhodius, Grenicus, Aesopus, and goodly Scamander, with Simois,
+where many a shield and helm had fallen, and many a hero of the
+race of demigods had bitten the dust. Phoebus Apollo turned the
+mouths of all these rivers together and made them flow for nine
+days against the wall, while Jove rained the whole time that he
+might wash it sooner into the sea. Neptune himself, trident in
+hand, surveyed the work and threw into the sea all the
+foundations of beams and stones which the Achaeans had laid with
+so much toil; he made all level by the mighty stream of the
+Hellespont, and then when he had swept the wall away he spread a
+great beach of sand over the place where it had been. This done
+he turned the rivers back into their old courses.
+</para>
+
+<para>
+This was what Neptune and Apollo were to do in after time; but as
+yet battle and turmoil were still raging round the wall till its
+timbers rang under the blows that rained upon them. The Argives,
+cowed by the scourge of Jove, were hemmed in at their ships in
+fear of Hector the mighty minister of Rout, who as heretofore
+fought with the force and fury of a whirlwind. As a lion or wild
+boar turns fiercely on the dogs and men that attack him, while
+these form solid wall and shower their javelins as they face
+him--his courage is all undaunted, but his high spirit will be
+the death of him; many a time does he charge at his pursuers to
+scatter them, and they fall back as often as he does so--even so
+did Hector go about among the host exhorting his men, and
+cheering them on to cross the trench.
+</para>
+
+<para>
+But the horses dared not do so, and stood neighing upon its
+brink, for the width frightened them. They could neither jump it
+nor cross it, for it had overhanging banks all round upon either
+side, above which there were the sharp stakes that the sons of
+the Achaeans had planted so close and strong as a defence against
+all who would assail it; a horse, therefore, could not get into
+it and draw his chariot after him, but those who were on foot
+kept trying their very utmost. Then Polydamas went up to Hector
+and said, "Hector, and you other captains of the Trojans and
+allies, it is madness for us to try and drive our horses across
+the trench; it will be very hard to cross, for it is full of
+sharp stakes, and beyond these there is the wall. Our horses
+therefore cannot get down into it, and would be of no use if they
+did; moreover it is a narrow place and we should come to harm.
+If, indeed, great Jove is minded to help the Trojans, and in his
+anger will utterly destroy the Achaeans, I would myself gladly
+see them perish now and here far from Argos; but if they should
+rally and we are driven back from the ships pell-mell into the
+trench there will be not so much as a man get back to the city to
+tell the tale. Now, therefore, let us all do as I say; let our
+squires hold our horses by the trench, but let us follow Hector
+in a body on foot, clad in full armour, and if the day of their
+doom is at hand the Achaeans will not be able to withstand us."
+</para>
+
+<para>
+Thus spoke Polydamas and his saying pleased Hector, who sprang in
+full armour to the ground, and all the other Trojans, when they
+saw him do so, also left their chariots. Each man then gave his
+horses over to his charioteer in charge to hold them ready for
+him at the trench. Then they formed themselves into companies,
+made themselves ready, and in five bodies followed their leaders.
+Those that went with Hector and Polydamas were the bravest and
+most in number, and the most determined to break through the wall
+and fight at the ships. Cebriones was also joined with them as
+third in command, for Hector had left his chariot in charge of a
+less valiant soldier. The next company was led by Paris,
+Alcathous, and Agenor; the third by Helenus and Deiphobus, two
+sons of Priam, and with them was the hero Asius--Asius, the son
+of Hyrtacus, whose great black horses of the breed that comes
+from the river Selleis had brought him from Arisbe. Aeneas, the
+valiant son of Anchises, led the fourth; he and the two sons of
+Antenor, Archelochus and Acamas, men well versed in all the arts
+of war. Sarpedon was captain over the allies, and took with him
+Glaucus and Asteropaeus whom he deemed most valiant after
+himself--for he was far the best man of them all. These helped to
+array one another in their ox-hide shields, and then charged
+straight at the Danaans, for they felt sure that they would not
+hold out longer and that they should themselves now fall upon the
+ships.
+</para>
+
+<para>
+The rest of the Trojans and their allies now followed the counsel
+of Polydamas but Asius, son of Hyrtacus, would not leave his
+horses and his esquire behind him; in his foolhardiness he took
+them on with him towards the ships, nor did he fail to come by
+his end in consequence. Nevermore was he to return to wind-beaten
+Ilius, exulting in his chariot and his horses; ere he could do
+so, death of ill-omened name had overshadowed him and he had
+fallen by the spear of Idomeneus the noble son of Deucalion. He
+had driven towards the left wing of the ships, by which way the
+Achaeans used to return with their chariots and horses from the
+plain. Hither he drove and found the gates with their doors
+opened wide, and the great bar down--for the gatemen kept them
+open so as to let those of their comrades enter who might be
+flying towards the ships. Hither of set purpose did he direct his
+horses, and his men followed him with a loud cry, for they felt
+sure that the Achaeans would not hold out longer, and that they
+should now fall upon the ships. Little did they know that at the
+gates they should find two of the bravest chieftains, proud sons
+of the fighting Lapithae--the one, Polypoetes, mighty son of
+Pirithous, and the other Leonteus, peer of murderous Mars. These
+stood before the gates like two high oak trees upon the
+mountains, that tower from their wide-spreading roots, and year
+after year battle with wind and rain--even so did these two men
+await the onset of great Asius confidently and without flinching.
+The Trojans led by him and by Iamenus, Orestes, Adamas the son of
+Asius, Thoon and Oenomaus, raised a loud cry of battle and made
+straight for the wall, holding their shields of dry ox-hide above
+their heads; for a while the two defenders remained inside and
+cheered the Achaeans on to stand firm in the defence of their
+ships; when, however, they saw that the Trojans were attacking
+the wall, while the Danaans were crying out for help and being
+routed, they rushed outside and fought in front of the gates like
+two wild boars upon the mountains that abide the attack of men
+and dogs, and charging on either side break down the wood all
+round them tearing it up by the roots, and one can hear the
+clattering of their tusks, till some one hits them and makes an
+end of them--even so did the gleaming bronze rattle about their
+breasts, as the weapons fell upon them; for they fought with
+great fury, trusting to their own prowess and to those who were
+on the wall above them. These threw great stones at their
+assailants in defence of themselves their tents and their ships.
+The stones fell thick as the flakes of snow which some fierce
+blast drives from the dark clouds and showers down in sheets upon
+the earth--even so fell the weapons from the hands alike of
+Trojans and Achaeans. Helmet and shield rang out as the great
+stones rained upon them, and Asius, the son of Hyrtacus, in his
+dismay cried aloud and smote his two thighs. "Father Jove," he
+cried, "of a truth you too are altogether given to lying. I made
+sure the Argive heroes could not withstand us, whereas like
+slim-waisted wasps, or bees that have their nests in the rocks by
+the wayside--they leave not the holes wherein they have built
+undefended, but fight for their little ones against all who would
+take them--even so these men, though they be but two, will not be
+driven from the gates, but stand firm either to slay or be
+slain."
+</para>
+
+<para>
+He spoke, but moved not the mind of Jove, whose counsel it then
+was to give glory to Hector. Meanwhile the rest of the Trojans
+were fighting about the other gates; I, however, am no god to be
+able to tell about all these things, for the battle raged
+everywhere about the stone wall as it were a fiery furnace. The
+Argives, discomfited though they were, were forced to defend
+their ships, and all the gods who were defending the Achaeans
+were vexed in spirit; but the Lapithae kept on fighting with
+might and main.
+</para>
+
+<para>
+Thereon Polypoetes, mighty son of Pirithous, hit Damasus with a
+spear upon his cheek-pierced helmet. The helmet did not protect
+him, for the point of the spear went through it, and broke the
+bone, so that the brain inside was scattered about, and he died
+fighting. He then slew Pylon and Ormenus. Leonteus, of the race
+of Mars, killed Hippomachus the son of Antimachus by striking him
+with his spear upon the girdle. He then drew his sword and sprang
+first upon Antiphates whom he killed in combat, and who fell face
+upwards on the earth. After him he killed Menon, Iamenus, and
+Orestes, and laid them low one after the other.
+</para>
+
+<para>
+While they were busy stripping the armour from these heroes, the
+youths who were led on by Polydamas and Hector (and these were
+the greater part and the most valiant of those that were trying
+to break through the wall and fire the ships) were still standing
+by the trench, uncertain what they should do; for they had seen a
+sign from heaven when they had essayed to cross it--a soaring
+eagle that flew skirting the left wing of their host, with a
+monstrous blood-red snake in its talons still alive and
+struggling to escape. The snake was still bent on revenge,
+wriggling and twisting itself backwards till it struck the bird
+that held it, on the neck and breast; whereon the bird being in
+pain, let it fall, dropping it into the middle of the host, and
+then flew down the wind with a sharp cry. The Trojans were struck
+with terror when they saw the snake, portent of aegis-bearing
+Jove, writhing in the midst of them, and Polydamas went up to
+Hector and said, "Hector, at our councils of war you are ever
+given to rebuke me, even when I speak wisely, as though it were
+not well, forsooth, that one of the people should cross your will
+either in the field or at the council board; you would have them
+support you always: nevertheless I will say what I think will be
+best; let us not now go on to fight the Danaans at their ships,
+for I know what will happen if this soaring eagle which skirted
+the left wing of our host with a monstrous blood-red snake in its
+talons (the snake being still alive) was really sent as an omen
+to the Trojans on their essaying to cross the trench. The eagle
+let go her hold; she did not succeed in taking it home to her
+little ones, and so will it be--with ourselves; even though by a
+mighty effort we break through the gates and wall of the
+Achaeans, and they give way before us, still we shall not return
+in good order by the way we came, but shall leave many a man
+behind us whom the Achaeans will do to death in defence of their
+ships. Thus would any seer who was expert in these matters, and
+was trusted by the people, read the portent."
+</para>
+
+<para>
+Hector looked fiercely at him and said, "Polydamas, I like not of
+your reading. You can find a better saying than this if you will.
+If, however, you have spoken in good earnest, then indeed has
+heaven robbed you of your reason. You would have me pay no heed
+to the counsels of Jove, nor to the promises he made me--and he
+bowed his head in confirmation; you bid me be ruled rather by the
+flight of wild-fowl. What care I whether they fly towards dawn or
+dark, and whether they be on my right hand or on my left? Let us
+put our trust rather in the counsel of great Jove, king of
+mortals and immortals. There is one omen, and one only--that a
+man should fight for his country. Why are you so fearful? Though
+we be all of us slain at the ships of the Argives you are not
+likely to be killed yourself, for you are not steadfast nor
+courageous. If you will not fight, or would talk others over from
+doing so, you shall fall forthwith before my spear."
+</para>
+
+<para>
+With these words he led the way, and the others followed after
+with a cry that rent the air. Then Jove the lord of thunder sent
+the blast of a mighty wind from the mountains of Ida, that bore
+the dust down towards the ships; he thus lulled the Achaeans into
+security, and gave victory to Hector and to the Trojans, who,
+trusting to their own might and to the signs he had shown them,
+essayed to break through the great wall of the Achaeans. They
+tore down the breastworks from the walls, and overthrew the
+battlements; they upheaved the buttresses, which the Achaeans had
+set in front of the wall in order to support it; when they had
+pulled these down they made sure of breaking through the wall,
+but the Danaans still showed no sign of giving ground; they still
+fenced the battlements with their shields of ox-hide, and hurled
+their missiles down upon the foe as soon as any came below the
+wall.
+</para>
+
+<para>
+The two Ajaxes went about everywhere on the walls cheering on the
+Achaeans, giving fair words to some while they spoke sharply to
+any one whom they saw to be remiss. "My friends," they cried,
+"Argives one and all--good bad and indifferent, for there was
+never fight yet, in which all were of equal prowess--there is now
+work enough, as you very well know, for all of you. See that you
+none of you turn in flight towards the ships, daunted by the
+shouting of the foe, but press forward and keep one another in
+heart, if it may so be that Olympian Jove the lord of lightning
+will vouchsafe us to repel our foes, and drive them back towards
+the city."
+</para>
+
+<para>
+Thus did the two go about shouting and cheering the Achaeans on.
+As the flakes that fall thick upon a winter's day, when Jove is
+minded to snow and to display these his arrows to mankind--he
+lulls the wind to rest, and snows hour after hour till he has
+buried the tops of the high mountains, the headlands that jut
+into the sea, the grassy plains, and the tilled fields of men;
+the snow lies deep upon the forelands, and havens of the grey
+sea, but the waves as they come rolling in stay it that it can
+come no further, though all else is wrapped as with a mantle, so
+heavy are the heavens with snow--even thus thickly did the stones
+fall on one side and on the other, some thrown at the Trojans,
+and some by the Trojans at the Achaeans; and the whole wall was
+in an uproar.
+</para>
+
+<para>
+Still the Trojans and brave Hector would not yet have broken down
+the gates and the great bar, had not Jove turned his son Sarpedon
+against the Argives as a lion against a herd of horned cattle.
+Before him he held his shield of hammered bronze, that the smith
+had beaten so fair and round, and had lined with ox hides which
+he had made fast with rivets of gold all round the shield; this
+he held in front of him, and brandishing his two spears came on
+like some lion of the wilderness, who has been long famished for
+want of meat and will dare break even into a well-fenced
+homestead to try and get at the sheep. He may find the shepherds
+keeping watch over their flocks with dogs and spears, but he is
+in no mind to be driven from the fold till he has had a try for
+it; he will either spring on a sheep and carry it off, or be hit
+by a spear from some strong hand--even so was Sarpedon fain to
+attack the wall and break down its battlements. Then he said to
+Glaucus son of Hippolochus, "Glaucus, why in Lycia do we receive
+especial honour as regards our place at table? Why are the
+choicest portions served us and our cups kept brimming, and why
+do men look up to us as though we were gods? Moreover we hold a
+large estate by the banks of the river Xanthus, fair with orchard
+lawns and wheat-growing land; it becomes us, therefore, to take
+our stand at the head of all the Lycians and bear the brunt of
+the fight, that one may say to another, 'Our princes in Lycia eat
+the fat of the land and drink best of wine, but they are fine
+fellows; they fight well and are ever at the front in battle.' My
+good friend, if, when we were once out of this fight, we could
+escape old age and death thenceforward and forever, I should
+neither press forward myself nor bid you do so, but death in ten
+thousand shapes hangs ever over our heads, and no man can elude
+him; therefore let us go forward and either win glory for
+ourselves, or yield it to another."
+</para>
+
+<para>
+Glaucus heeded his saying, and the pair forthwith led on the host
+of Lycians. Menestheus son of Peteos was dismayed when he saw
+them, for it was against his part of the wall that they came--
+bringing destruction with them; he looked along the wall for some
+chieftain to support his comrades and saw the two Ajaxes, men
+ever eager for the fray, and Teucer, who had just come from his
+tent, standing near them; but he could not make his voice heard
+by shouting to them, so great an uproar was there from crashing
+shields and helmets and the battering of gates with a din which
+reached the skies. For all the gates had been closed, and the
+Trojans were hammering at them to try and break their way through
+them. Menestheus, therefore, sent Thootes with a message to Ajax.
+"Run, good Thootes," he said, "and call Ajax, or better still bid
+both come, for it will be all over with us here directly; the
+leaders of the Lycians are upon us, men who have ever fought
+desperately heretofore. But if they have too much on their hands
+to let them come, at any rate let Ajax son of Telamon do so, and
+let Teucer, the famous bowman, come with him."
+</para>
+
+<para>
+The messenger did as he was told, and set off running along the
+wall of the Achaeans. When he reached the Ajaxes he said to them,
+"Sirs, princes of the Argives, the son of noble Peteos bids you
+come to him for a while and help him. You had better both come if
+you can, or it will be all over with him directly; the leaders of
+the Lycians are upon him, men who have ever fought desperately
+heretofore; if you have too much on your hands to let both come,
+at any rate let Ajax, son of Telamon, do so, and let Teucer, the
+famous bowman, come with him."
+</para>
+
+<para>
+Great Ajax son of Telamon heeded the message, and at once spoke
+to the son of Oileus. "Ajax," said he, "do you two, yourself and
+brave Lycomedes, stay here and keep the Danaans in heart to fight
+their hardest. I will go over yonder, and bear my part in the
+fray, but I will come back here at once as soon as I have given
+them the help they need."
+</para>
+
+<para>
+With this, Ajax son of Telamon set off, and Teucer, his brother
+by the same father, went also, with Pandion to carry Teucer's
+bow. They went along inside the wall, and when they came to the
+tower where Menestheus was (and hard pressed indeed did they find
+him) the brave captains and leaders of the Lycians were storming
+the battlements as it were a thick dark cloud, fighting in close
+quarters, and raising the battle-cry aloud.
+</para>
+
+<para>
+First, Ajax son of Telamon killed brave Epicles, a comrade of
+Sarpedon, hitting him with a jagged stone that lay by the
+battlements at the very top of the wall. As men now are, even one
+who is in the bloom of youth could hardly lift it with his two
+hands, but Ajax raised it high aloft and flung it down, smashing
+Epicles' four-crested helmet so that the bones of his head were
+crushed to pieces, and he fell from the high wall as though he
+were diving, with no more life left in him. Then Teucer wounded
+Glaucus the brave son of Hippolochus as he was coming on to
+attack the wall. He saw his shoulder bare and aimed an arrow at
+it, which made Glaucus leave off fighting. Thereon he sprang
+covertly down for fear some of the Achaeans might see that he was
+wounded and taunt him. Sarpedon was stung with grief when he saw
+Glaucus leave him, still he did not leave off fighting, but aimed
+his spear at Alcmaon the son of Thestor and hit him. He drew his
+spear back again and Alcmaon came down headlong after it with his
+bronzed armour rattling round him. Then Sarpedon seized the
+battlement in his strong hands, and tugged at it till it all gave
+way together, and a breach was made through which many might
+pass.
+</para>
+
+<para>
+Ajax and Teucer then both of them attacked him. Teucer hit him
+with an arrow on the band that bore the shield which covered his
+body, but Jove saved his son from destruction that he might not
+fall by the ships' sterns. Meanwhile Ajax sprang on him and
+pierced his shield, but the spear did not go clean through,
+though it hustled him back that he could come on no further. He
+therefore retired a little space from the battlement, yet without
+losing all his ground, for he still thought to cover himself with
+glory. Then he turned round and shouted to the brave Lycians
+saying, "Lycians, why do you thus fail me? For all my prowess I
+cannot break through the wall and open a way to the ships
+single-handed. Come close on behind me, for the more there are of
+us the better."
+</para>
+
+<para>
+The Lycians, shamed by his rebuke, pressed closer round him who
+was their counsellor and their king. The Argives on their part
+got their men in fighting order within the wall, and there was a
+deadly struggle between them. The Lycians could not break through
+the wall and force their way to the ships, nor could the Danaans
+drive the Lycians from the wall now that they had once reached
+it. As two men, measuring-rods in hand, quarrel about their
+boundaries in a field that they own in common, and stickle for
+their rights though they be but in a mere strip, even so did the
+battlements now serve as a bone of contention, and they beat one
+another's round shields for their possession. Many a man's body
+was wounded with the pitiless bronze, as he turned round and
+bared his back to the foe, and many were struck clean through
+their shields; the wall and battlements were everywhere deluged
+with the blood alike of Trojans and of Achaeans. But even so the
+Trojans could not rout the Achaeans, who still held on; and as
+some honest hard-working woman weighs wool in her balance and
+sees that the scales be true, for she would gain some pitiful
+earnings for her little ones, even so was the fight balanced
+evenly between them till the time came when Jove gave the greater
+glory to Hector son of Priam, who was first to spring towards the
+wall of the Achaeans. When he had done so, he cried aloud to the
+Trojans, "Up, Trojans, break the wall of the Argives, and fling
+fire upon their ships."
+</para>
+
+<para>
+Thus did he hound them on, and in one body they rushed straight
+at the wall as he had bidden them, and scaled the battlements
+with sharp spears in their hands. Hector laid hold of a stone
+that lay just outside the gates and was thick at one end but
+pointed at the other; two of the best men in a town, as men now
+are, could hardly raise it from the ground and put it on to a
+waggon, but Hector lifted it quite easily by himself, for the son
+of scheming Saturn made it light for him. As a shepherd picks up
+a ram's fleece with one hand and finds it no burden, so easily
+did Hector lift the great stone and drive it right at the doors
+that closed the gates so strong and so firmly set. These doors
+were double and high, and were kept closed by two cross-bars to
+which there was but one key. When he had got close up to them,
+Hector strode towards them that his blow might gain in force and
+struck them in the middle, leaning his whole weight against them.
+He broke both hinges, and the stone fell inside by reason of its
+great weight. The portals re-echoed with the sound, the bars held
+no longer, and the doors flew open, one one way, and the other
+the other, through the force of the blow. Then brave Hector
+leaped inside with a face as dark as that of flying night. The
+gleaming bronze flashed fiercely about his body and he had two
+spears in his hand. None but a god could have withstood him as he
+flung himself into the gateway, and his eyes glared like fire.
+Then he turned round towards the Trojans and called on them to
+scale the wall, and they did as he bade them--some of them at
+once climbing over the wall, while others passed through the
+gates. The Danaans then fled panic-stricken towards their ships,
+and all was uproar and confusion.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK XIII</title>
+
+<para>
+NOW when Jove had thus brought Hector and the Trojans to the
+ships, he left them to their never-ending toil, and turned his
+keen eyes away, looking elsewhither towards the horse-breeders of
+Thrace, the Mysians, fighters at close quarters, the noble
+Hippemolgi, who live on milk, and the Abians, justest of mankind.
+He no longer turned so much as a glance towards Troy, for he did
+not think that any of the immortals would go and help either
+Trojans or Danaans.
+</para>
+
+<para>
+But King Neptune had kept no blind look-out; he had been looking
+admiringly on the battle from his seat on the topmost crests of
+wooded Samothrace, whence he could see all Ida, with the city of
+Priam and the ships of the Achaeans. He had come from under the
+sea and taken his place here, for he pitied the Achaeans who were
+being overcome by the Trojans; and he was furiously angry with
+Jove.
+</para>
+
+<para>
+Presently he came down from his post on the mountain top, and as
+he strode swiftly onwards the high hills and the forest quaked
+beneath the tread of his immortal feet. Three strides he took,
+and with the fourth he reached his goal--Aegae, where is his
+glittering golden palace, imperishable, in the depths of the sea.
+When he got there, he yoked his fleet brazen-footed steeds with
+their manes of gold all flying in the wind; he clothed himself in
+raiment of gold, grasped his gold whip, and took his stand upon
+his chariot. As he went his way over the waves the sea-monsters
+left their lairs, for they knew their lord, and came gambolling
+round him from every quarter of the deep, while the sea in her
+gladness opened a path before his chariot. So lightly did the
+horses fly that the bronze axle of the car was not even wet
+beneath it; and thus his bounding steeds took him to the ships of
+the Achaeans.
+</para>
+
+<para>
+Now there is a certain huge cavern in the depths of the sea
+midway between Tenedos and rocky Imbrus; here Neptune lord of the
+earthquake stayed his horses, unyoked them, and set before them
+their ambrosial forage. He hobbled their feet with hobbles of
+gold which none could either unloose or break, so that they might
+stay there in that place until their lord should return. This
+done he went his way to the host of the Achaeans.
+</para>
+
+<para>
+Now the Trojans followed Hector son of Priam in close array like
+a storm-cloud or flame of fire, fighting with might and main and
+raising the cry battle; for they deemed that they should take the
+ships of the Achaeans and kill all their chiefest heroes then and
+there. Meanwhile earth-encircling Neptune lord of the earthquake
+cheered on the Argives, for he had come up out of the sea and had
+assumed the form and voice of Calchas.
+</para>
+
+<para>
+First he spoke to the two Ajaxes, who were doing their best
+already, and said, "Ajaxes, you two can be the saving of the
+Achaeans if you will put out all your strength and not let
+yourselves be daunted. I am not afraid that the Trojans, who have
+got over the wall in force, will be victorious in any other part,
+for the Achaeans can hold all of them in check, but I much fear
+that some evil will befall us here where furious Hector, who
+boasts himself the son of great Jove himself, is leading them on
+like a pillar of flame. May some god, then, put it into your
+hearts to make a firm stand here, and to incite others to do the
+like. In this case you will drive him from the ships even though
+he be inspired by Jove himself."
+</para>
+
+<para>
+As he spoke the earth-encircling lord of the earthquake struck
+both of them with his sceptre and filled their hearts with
+daring. He made their legs light and active, as also their hands
+and their feet. Then, as the soaring falcon poises on the wing
+high above some sheer rock, and presently swoops down to chase
+some bird over the plain, even so did Neptune lord of the
+earthquake wing his flight into the air and leave them. Of the
+two, swift Ajax son of Oileus was the first to know who it was
+that had been speaking with them, and said to Ajax son of
+Telamon, "Ajax, this is one of the gods that dwell on Olympus,
+who in the likeness of the prophet is bidding us fight hard by
+our ships. It was not Calchas the seer and diviner of omens; I
+knew him at once by his feet and knees as he turned away, for the
+gods are soon recognised. Moreover I feel the lust of battle burn
+more fiercely within me, while my hands and my feet under me are
+more eager for the fray."
+</para>
+
+<para>
+And Ajax son of Telamon answered, "I too feel my hands grasp my
+spear more firmly; my strength is greater, and my feet more
+nimble; I long, moreover, to meet furious Hector son of Priam,
+even in single combat."
+</para>
+
+<para>
+Thus did they converse, exulting in the hunger after battle with
+which the god had filled them. Meanwhile the earth-encircler
+roused the Achaeans, who were resting in the rear by the ships
+overcome at once by hard fighting and by grief at seeing that the
+Trojans had got over the wall in force. Tears began falling from
+their eyes as they beheld them, for they made sure that they
+should not escape destruction; but the lord of the earthquake
+passed lightly about among them and urged their battalions to the
+front.
+</para>
+
+<para>
+First he went up to Teucer and Leitus, the hero Peneleos, and
+Thoas and Deipyrus; Meriones also and Antilochus, valiant
+warriors; all did he exhort. "Shame on you young Argives," he
+cried, "it was on your prowess I relied for the saving of our
+ships; if you fight not with might and main, this very day will
+see us overcome by the Trojans. Of a truth my eyes behold a great
+and terrible portent which I had never thought to see--the
+Trojans at our ships--they, who were heretofore like
+panic-stricken hinds, the prey of jackals and wolves in a forest,
+with no strength but in flight for they cannot defend themselves.
+Hitherto the Trojans dared not for one moment face the attack of
+the Achaeans, but now they have sallied far from their city and
+are fighting at our very ships through the cowardice of our
+leader and the disaffection of the people themselves, who in
+their discontent care not to fight in defence of the ships but
+are being slaughtered near them. True, King Agamemnon son of
+Atreus is the cause of our disaster by having insulted the son of
+Peleus, still this is no reason why we should leave off fighting.
+Let us be quick to heal, for the hearts of the brave heal
+quickly. You do ill to be thus remiss, you, who are the finest
+soldiers in our whole army. I blame no man for keeping out of
+battle if he is a weakling, but I am indignant with such men as
+you are. My good friends, matters will soon become even worse
+through this slackness; think, each one of you, of his own honour
+and credit, for the hazard of the fight is extreme. Great Hector
+is now fighting at our ships; he has broken through the gates and
+the strong bolt that held them."
+</para>
+
+<para>
+Thus did the earth-encircler address the Achaeans and urge them
+on. Thereon round the two Ajaxes there gathered strong bands of
+men, of whom not even Mars nor Minerva, marshaller of hosts could
+make light if they went among them, for they were the picked men
+of all those who were now awaiting the onset of Hector and the
+Trojans. They made a living fence, spear to spear, shield to
+shield, buckler to buckler, helmet to helmet, and man to man. The
+horse-hair crests on their gleaming helmets touched one another
+as they nodded forward, so closely serried were they; the spears
+they brandished in their strong hands were interlaced, and their
+hearts were set on battle.
+</para>
+
+<para>
+The Trojans advanced in a dense body, with Hector at their head
+pressing right on as a rock that comes thundering down the side
+of some mountain from whose brow the winter torrents have torn
+it; the foundations of the dull thing have been loosened by
+floods of rain, and as it bounds headlong on its way it sets the
+whole forest in an uproar; it swerves neither to right nor left
+till it reaches level ground, but then for all its fury it can go
+no further--even so easily did Hector for a while seem as though
+he would career through the tents and ships of the Achaeans till
+he had reached the sea in his murderous course; but the closely
+serried battalions stayed him when he reached them, for the sons
+of the Achaeans thrust at him with swords and spears pointed at
+both ends, and drove him from them so that he staggered and gave
+ground; thereon he shouted to the Trojans, "Trojans, Lycians, and
+Dardanians, fighters in close combat, stand firm: the Achaeans
+have set themselves as a wall against me, but they will not check
+me for long; they will give ground before me if the mightiest of
+the gods, the thundering spouse of Juno, has indeed inspired my
+onset."
+</para>
+
+<para>
+With these words he put heart and soul into them all. Deiphobus
+son of Priam went about among them intent on deeds of daring with
+his round shield before him, under cover of which he strode
+quickly forward. Meriones took aim at him with a spear, nor did
+he fail to hit the broad orb of ox-hide; but he was far from
+piercing it for the spear broke in two pieces long ere he could
+do so; moreover Deiphobus had seen it coming and had held his
+shield well away from him. Meriones drew back under cover of his
+comrades, angry alike at having failed to vanquish Deiphobus, and
+having broken his spear. He turned therefore towards the ships
+and tents to fetch a spear which he had left behind in his tent.
+</para>
+
+<para>
+The others continued fighting, and the cry of battle rose up into
+the heavens. Teucer son of Telamon was the first to kill his man,
+to wit, the warrior Imbrius, son of Mentor, rich in horses.
+Until the Achaeans came he had lived in Pedaeum, and had married
+Medesicaste, a bastard daughter of Priam; but on the arrival of
+the Danaan fleet he had gone back to Ilius, and was a great man
+among the Trojans, dwelling near Priam himself, who gave him like
+honour with his own sons. The son of Telamon now struck him under
+the ear with a spear which he then drew back again, and Imbrius
+fell headlong as an ash-tree when it is felled on the crest of
+some high mountain beacon, and its delicate green foliage comes
+toppling down to the ground. Thus did he fall with his
+bronze-dight armour ringing harshly round him, and Teucer sprang
+forward with intent to strip him of his armour; but as he was
+doing so, Hector took aim at him with a spear. Teucer saw the
+spear coming and swerved aside, whereon it hit Amphimachus, son
+of Cteatus son of Actor, in the chest as he was coming into
+battle, and his armour rang rattling round him as he fell heavily
+to the ground. Hector sprang forward to take Amphimachus's helmet
+from off his temples, and in a moment Ajax threw a spear at him,
+but did not wound him, for he was encased all over in his
+terrible armour; nevertheless the spear struck the boss of his
+shield with such force as to drive him back from the two corpses,
+which the Achaeans then drew off. Stichius and Menestheus,
+captains of the Athenians, bore away Amphimachus to the host of
+the Achaeans, while the two brave and impetuous Ajaxes did the
+like by Imbrius. As two lions snatch a goat from the hounds that
+have it in their fangs, and bear it through thick brushwood high
+above the ground in their jaws, thus did the Ajaxes bear aloft
+the body of Imbrius, and strip it of its armour. Then the son of
+Oileus severed the head from the neck in revenge for the death of
+Amphimachus, and sent it whirling over the crowd as though it had
+been a ball, till it fell in the dust at Hector's feet.
+</para>
+
+<para>
+Neptune was exceedingly angry that his grandson Amphimachus
+should have fallen; he therefore went to the tents and ships of
+the Achaeans to urge the Danaans still further, and to devise
+evil for the Trojans. Idomeneus met him, as he was taking leave
+of a comrade, who had just come to him from the fight, wounded in
+the knee. His fellow-soldiers bore him off the field, and
+Idomeneus having given orders to the physicians went on to his
+tent, for he was still thirsting for battle. Neptune spoke in the
+likeness and with the voice of Thoas son of Andraemon who ruled
+the Aetolians of all Pleuron and high Calydon, and was honoured
+among his people as though he were a god. "Idomeneus," said he,
+"lawgiver to the Cretans, what has now become of the threats with
+which the sons of the Achaeans used to threaten the Trojans?"
+</para>
+
+<para>
+And Idomeneus chief among the Cretans answered, "Thoas, no one,
+so far as I know, is in fault, for we can all fight. None are
+held back neither by fear nor slackness, but it seems to be the
+will of almighty Jove that the Achaeans should perish
+ingloriously here far from Argos: you, Thoas, have been always
+staunch, and you keep others in heart if you see any fail in
+duty; be not then remiss now, but exhort all to do their utmost."
+</para>
+
+<para>
+To this Neptune lord of the earthquake made answer, "Idomeneus,
+may he never return from Troy, but remain here for dogs to batten
+upon, who is this day wilfully slack in fighting. Get your armour
+and go, we must make all haste together if we may be of any use,
+though we are only two. Even cowards gain courage from
+companionship, and we two can hold our own with the bravest."
+</para>
+
+<para>
+Therewith the god went back into the thick of the fight, and
+Idomeneus when he had reached his tent donned his armour, grasped
+his two spears, and sallied forth. As the lightning which the son
+of Saturn brandishes from bright Olympus when he would show a
+sign to mortals, and its gleam flashes far and wide--even so did
+his armour gleam about him as he ran. Meriones his sturdy squire
+met him while he was still near his tent (for he was going to
+fetch his spear) and Idomeneus said:
+</para>
+
+<para>
+"Meriones, fleet son of Molus, best of comrades, why have you
+left the field? Are you wounded, and is the point of the weapon
+hurting you? or have you been sent to fetch me? I want no
+fetching; I had far rather fight than stay in my tent."
+</para>
+
+<para>
+"Idomeneus," answered Meriones, "I come for a spear, if I can
+find one in my tent; I have broken the one I had, in throwing it
+at the shield of Deiphobus."
+</para>
+
+<para>
+And Idomeneus captain of the Cretans answered, "You will find one
+spear, or twenty if you so please, standing up against the end
+wall of my tent. I have taken them from Trojans whom I have
+killed, for I am not one to keep my enemy at arm's length;
+therefore I have spears, bossed shields, helmets, and burnished
+corslets."
+</para>
+
+<para>
+Then Meriones said, "I too in my tent and at my ship have spoils
+taken from the Trojans, but they are not at hand. I have been at
+all times valorous, and wherever there has been hard fighting
+have held my own among the foremost. There may be those among the
+Achaeans who do not know how I fight, but you know it well enough
+yourself."
+</para>
+
+<para>
+Idomeneus answered, "I know you for a brave man: you need not
+tell me. If the best men at the ships were being chosen to go on
+an ambush--and there is nothing like this for showing what a man
+is made of; it comes out then who is cowardly and who brave; the
+coward will change colour at every touch and turn; he is full of
+fears, and keeps shifting his weight first on one knee and then
+on the other; his heart beats fast as he thinks of death, and one
+can hear the chattering of his teeth; whereas the brave man will
+not change colour nor be frightened on finding himself in ambush,
+but is all the time longing to go into action--if the best men
+were being chosen for such a service, no one could make light of
+your courage nor feats of arms. If you were struck by a dart or
+smitten in close combat, it would not be from behind, in your
+neck nor back, but the weapon would hit you in the chest or belly
+as you were pressing forward to a place in the front ranks. But
+let us no longer stay here talking like children, lest we be ill
+spoken of; go, fetch your spear from the tent at once."
+</para>
+
+<para>
+On this Meriones, peer of Mars, went to the tent and got himself
+a spear of bronze. He then followed after Idomeneus, big with
+great deeds of valour. As when baneful Mars sallies forth to
+battle, and his son Panic so strong and dauntless goes with him,
+to strike terror even into the heart of a hero--the pair have
+gone from Thrace to arm themselves among the Ephyri or the brave
+Phlegyans, but they will not listen to both the contending hosts,
+and will give victory to one side or to the other--even so did
+Meriones and Idomeneus, captains of men, go out to battle clad in
+their bronze armour. Meriones was first to speak. "Son of
+Deucalion," said he, "where would you have us begin fighting? On
+the right wing of the host, in the centre, or on the left wing,
+where I take it the Achaeans will be weakest?"
+</para>
+
+<para>
+Idomeneus answered, "There are others to defend the centre--the
+two Ajaxes and Teucer, who is the finest archer of all the
+Achaeans, and is good also in a hand-to-hand fight. These will
+give Hector son of Priam enough to do; fight as he may, he will
+find it hard to vanquish their indomitable fury, and fire the
+ships, unless the son of Saturn fling a firebrand upon them with
+his own hand. Great Ajax son of Telamon will yield to no man who
+is in mortal mould and eats the grain of Ceres, if bronze and
+great stones can overthrow him. He would not yield even to
+Achilles in hand-to-hand fight, and in fleetness of foot there is
+none to beat him; let us turn therefore towards the left wing,
+that we may know forthwith whether we are to give glory to some
+other, or he to us."
+</para>
+
+<para>
+Meriones, peer of fleet Mars, then led the way till they came to
+the part of the host which Idomeneus had named.
+</para>
+
+<para>
+Now when the Trojans saw Idomeneus coming on like a flame of
+fire, him and his squire clad in their richly wrought armour,
+they shouted and made towards him all in a body, and a furious
+hand-to-hand fight raged under the ships' sterns. Fierce as the
+shrill winds that whistle upon a day when dust lies deep on the
+roads, and the gusts raise it into a thick cloud--even such was
+the fury of the combat, and might and main did they hack at each
+other with spear and sword throughout the host. The field
+bristled with the long and deadly spears which they bore.
+Dazzling was the sheen of their gleaming helmets, their
+fresh-burnished breastplates, and glittering shields as they
+joined battle with one another. Iron indeed must be his courage
+who could take pleasure in the sight of such a turmoil, and look
+on it without being dismayed.
+</para>
+
+<para>
+Thus did the two mighty sons of Saturn devise evil for mortal
+heroes. Jove was minded to give victory to the Trojans and to
+Hector, so as to do honour to fleet Achilles, nevertheless he did
+not mean to utterly overthrow the Achaean host before Ilius, and
+only wanted to glorify Thetis and her valiant son. Neptune on the
+other hand went about among the Argives to incite them, having
+come up from the grey sea in secret, for he was grieved at seeing
+them vanquished by the Trojans, and was furiously angry with
+Jove. Both were of the same race and country, but Jove was elder
+born and knew more, therefore Neptune feared to defend the
+Argives openly, but in the likeness of man, he kept on
+encouraging them throughout their host. Thus, then, did these two
+devise a knot of war and battle, that none could unloose or
+break, and set both sides tugging at it, to the failing of men's
+knees beneath them.
+</para>
+
+<para>
+And now Idomeneus, though his hair was already flecked with grey,
+called loud on the Danaans and spread panic among the Trojans as
+he leaped in among them. He slew Othryoneus from Cabesus, a
+sojourner, who had but lately come to take part in the war. He
+sought Cassandra, the fairest of Priam's daughters, in marriage,
+but offered no gifts of wooing, for he promised a great thing, to
+wit, that he would drive the sons of the Achaeans willy nilly
+from Troy; old King Priam had given his consent and promised her
+to him, whereon he fought on the strength of the promises thus
+made to him. Idomeneus aimed a spear, and hit him as he came
+striding on. His cuirass of bronze did not protect him, and the
+spear stuck in his belly, so that he fell heavily to the ground.
+Then Idomeneus vaunted over him saying, "Othryoneus, there is no
+one in the world whom I shall admire more than I do you, if you
+indeed perform what you have promised Priam son of Dardanus in
+return for his daughter. We too will make you an offer; we will
+give you the loveliest daughter of the son of Atreus, and will
+bring her from Argos for you to marry, if you will sack the
+goodly city of Ilius in company with ourselves; so come along
+with me, that we may make a covenant at the ships about the
+marriage, and we will not be hard upon you about gifts of
+wooing."
+</para>
+
+<para>
+With this Idomeneus began dragging him by the foot through the
+thick of the fight, but Asius came up to protect the body, on
+foot, in front of his horses which his esquire drove so close
+behind him that he could feel their breath upon his shoulder. He
+was longing to strike down Idomeneus, but ere he could do so
+Idomeneus smote him with his spear in the throat under the chin,
+and the bronze point went clean through it. He fell as an oak, or
+poplar, or pine which shipwrights have felled for ship's timber
+upon the mountains with whetted axes--even thus did he lie full
+length in front of his chariot and horses, grinding his teeth and
+clutching at the bloodstained dust. His charioteer was struck
+with panic and did not dare turn his horses round and escape:
+thereupon Antilochus hit him in the middle of his body with a
+spear; his cuirass of bronze did not protect him, and the spear
+stuck in his belly. He fell gasping from his chariot and
+Antilochus, great Nestor's son, drove his horses from the Trojans
+to the Achaeans.
+</para>
+
+<para>
+Deiphobus then came close up to Idomeneus to avenge Asius, and
+took aim at him with a spear, but Idomeneus was on the look-out
+and avoided it, for he was covered by the round shield he always
+bore--a shield of oxhide and bronze with two arm-rods on the
+inside. He crouched under cover of this, and the spear flew over
+him, but the shield rang out as the spear grazed it, and the
+weapon sped not in vain from the strong hand of Deiphobus, for it
+struck Hypsenor son of Hippasus, shepherd of his people, in the
+liver under the midriff, and his limbs failed beneath him.
+Deiphobus vaunted over him and cried with a loud voice saying,
+"Of a truth Asius has not fallen unavenged; he will be glad even
+while passing into the house of Hades, strong warden of the gate,
+that I have sent some one to escort him."
+</para>
+
+<para>
+Thus did he vaunt, and the Argives were stung by his saying.
+Noble Antilochus was more angry than any one, but grief did not
+make him forget his friend and comrade. He ran up to him,
+bestrode him, and covered him with his shield; then two of his
+staunch comrades, Mecisteus son of Echius, and Alastor, stooped
+down, and bore him away groaning heavily to the ships. But
+Idomeneus ceased not his fury. He kept on striving continually
+either to enshroud some Trojan in the darkness of death, or
+himself to fall while warding off the evil day from the Achaeans.
+Then fell Alcathous son of noble Aesyetes; he was son-in-law to
+Anchises, having married his eldest daughter Hippodameia, who was
+the darling of her father and mother, and excelled all her
+generation in beauty, accomplishments, and understanding,
+wherefore the bravest man in all Troy had taken her to wife--him
+did Neptune lay low by the hand of Idomeneus, blinding his bright
+eyes and binding his strong limbs in fetters so that he could
+neither go back nor to one side, but stood stock still like
+pillar or lofty tree when Idomeneus struck him with a spear in
+the middle of his chest. The coat of mail that had hitherto
+protected his body was now broken, and rang harshly as the spear
+tore through it. He fell heavily to the ground, and the spear
+stuck in his heart, which still beat, and made the butt-end of
+the spear quiver till dread Mars put an end to his life.
+Idomeneus vaunted over him and cried with a loud voice saying,
+"Deiphobus, since you are in a mood to vaunt, shall we cry quits
+now that we have killed three men to your one? Nay, sir, stand in
+fight with me yourself, that you may learn what manner of
+Jove-begotten man am I that have come hither. Jove first begot
+Minos, chief ruler in Crete, and Minos in his turn begot a son,
+noble Deucalion. Deucalion begot me to be a ruler over many men
+in Crete, and my ships have now brought me hither, to be the bane
+of yourself, your father, and the Trojans."
+</para>
+
+<para>
+Thus did he speak, and Deiphobus was in two minds, whether to go
+back and fetch some other Trojan to help him, or to take up the
+challenge single-handed. In the end, he deemed it best to go and
+fetch Aeneas, whom he found standing in the rear, for he had long
+been aggrieved with Priam because in spite of his brave deeds he
+did not give him his due share of honour. Deiphobus went up to
+him and said, "Aeneas, prince among the Trojans, if you know any
+ties of kinship, help me now to defend the body of your sister's
+husband; come with me to the rescue of Alcathous, who being
+husband to your sister brought you up when you were a child in
+his house, and now Idomeneus has slain him."
+</para>
+
+<para>
+With these words he moved the heart of Aeneas, and he went in
+pursuit of Idomeneus, big with great deeds of valour; but
+Idomeneus was not to be thus daunted as though he were a mere
+child; he held his ground as a wild boar at bay upon the
+mountains, who abides the coming of a great crowd of men in some
+lonely place--the bristles stand upright on his back, his eyes
+flash fire, and he whets his tusks in his eagerness to defend
+himself against hounds and men--even so did famed Idomeneus hold
+his ground and budge not at the coming of Aeneas. He cried aloud
+to his comrades looking towards Ascalaphus, Aphareus, Deipyrus,
+Meriones, and Antilochus, all of them brave soldiers--"Hither my
+friends," he cried, "and leave me not single-handed--I go in
+great fear by fleet Aeneas, who is coming against me, and is a
+redoubtable dispenser of death battle. Moreover he is in the
+flower of youth when a man's strength is greatest; if I was of
+the same age as he is and in my present mind, either he or I
+should soon bear away the prize of victory."
+</para>
+
+<para>
+On this, all of them as one man stood near him, shield on
+shoulder. Aeneas on the other side called to his comrades,
+looking towards Deiphobus, Paris, and Agenor, who were leaders of
+the Trojans along with himself, and the people followed them as
+sheep follow the ram when they go down to drink after they have
+been feeding, and the heart of the shepherd is glad--even so was
+the heart of Aeneas gladdened when he saw his people follow him.
+</para>
+
+<para>
+Then they fought furiously in close combat about the body of
+Alcathous, wielding their long spears; and the bronze armour
+about their bodies rang fearfully as they took aim at one another
+in the press of the fight, while the two heroes Aeneas and
+Idomeneus, peers of Mars, outvied everyone in their desire to
+hack at each other with sword and spear. Aeneas took aim first,
+but Idomeneus was on the lookout and avoided the spear, so that
+it sped from Aeneas' strong hand in vain, and fell quivering in
+the ground. Idomeneus meanwhile smote Oenomaus in the middle of
+his belly, and broke the plate of his corslet, whereon his bowels
+came gushing out and he clutched the earth in the palms of his
+hands as he fell sprawling in the dust. Idomeneus drew his spear
+out of the body, but could not strip him of the rest of his
+armour for the rain of darts that were showered upon him:
+moreover his strength was now beginning to fail him so that he
+could no longer charge, and could neither spring forward to
+recover his own weapon nor swerve aside to avoid one that was
+aimed at him; therefore, though he still defended himself in
+hand-to-hand fight, his heavy feet could not bear him swiftly out
+of the battle. Deiphobus aimed a spear at him as he was
+retreating slowly from the field, for his bitterness against him
+was as fierce as ever, but again he missed him, and hit
+Ascalaphus, the son of Mars; the spear went through his shoulder,
+and he clutched the earth in the palms of his hands as he fell
+sprawling in the dust.
+</para>
+
+<para>
+Grim Mars of awful voice did not yet know that his son had
+fallen, for he was sitting on the summits of Olympus under the
+golden clouds, by command of Jove, where the other gods were also
+sitting, forbidden to take part in the battle. Meanwhile men
+fought furiously about the body. Deiphobus tore the helmet from
+off his head, but Meriones sprang upon him, and struck him on the
+arm with a spear so that the visored helmet fell from his hand
+and came ringing down upon the ground. Thereon Meriones sprang
+upon him like a vulture, drew the spear from his shoulder, and
+fell back under cover of his men. Then Polites, own brother of
+Deiphobus passed his arms around his waist, and bore him away
+from the battle till he got to his horses that were standing in
+the rear of the fight with the chariot and their driver. These
+took him towards the city groaning and in great pain, with the
+blood flowing from his arm.
+</para>
+
+<para>
+The others still fought on, and the battle-cry rose to heaven
+without ceasing. Aeneas sprang on Aphareus son of Caletor, and
+struck him with a spear in his throat which was turned towards
+him; his head fell on one side, his helmet and shield came down
+along with him, and death, life's foe, was shed around him.
+Antilochus spied his chance, flew forward towards Thoon, and
+wounded him as he was turning round. He laid open the vein that
+runs all the way up the back to the neck; he cut this vein clean
+away throughout its whole course, and Thoon fell in the dust face
+upwards, stretching out his hands imploringly towards his
+comrades. Antilochus sprang upon him and stripped the armour from
+his shoulders, glaring round him fearfully as he did so. The
+Trojans came about him on every side and struck his broad and
+gleaming shield, but could not wound his body, for Neptune stood
+guard over the son of Nestor, though the darts fell thickly round
+him. He was never clear of the foe, but was always in the thick
+of the fight; his spear was never idle; he poised and aimed it in
+every direction, so eager was he to hit someone from a distance
+or to fight him hand to hand.
+</para>
+
+<para>
+As he was thus aiming among the crowd, he was seen by Adamas, son
+of Asius, who rushed towards him and struck him with a spear in
+the middle of his shield, but Neptune made its point without
+effect, for he grudged him the life of Antilochus. One half,
+therefore, of the spear stuck fast like a charred stake in
+Antilochus's shield, while the other lay on the ground. Adamas
+then sought shelter under cover of his men, but Meriones followed
+after and hit him with a spear midway between the private parts
+and the navel, where a wound is particualrly painful to wretched
+mortals. There did Meriones transfix him, and he writhed
+convulsively about the spear as some bull whom mountain herdsmen
+have bound with ropes of withes and are taking away perforce.
+Even so did he move convulsively for a while, but not for very
+long, till Meriones came up and drew the spear out of his body,
+and his eyes were veiled in darkness.
+</para>
+
+<para>
+Helenus then struck Deipyrus with a great Thracian sword, hitting
+him on the temple in close combat and tearing the helmet from his
+head; the helmet fell to the ground, and one of those who were
+fighting on the Achaean side took charge of it as it rolled at
+his feet, but the eyes of Deipyrus were closed in the darkness of
+death.
+</para>
+
+<para>
+On this Menelaus was grieved, and made menacingly towards
+Helenus, brandishing his spear; but Helenus drew his bow, and the
+two attacked one another at one and the same moment, the one with
+his spear, and the other with his bow and arrow. The son of Priam
+hit the breastplate of Menelaus's corslet, but the arrow glanced
+from off it. As black beans or pulse come pattering down on to a
+threshing-floor from the broad winnowing-shovel, blown by shrill
+winds and shaken by the shovel--even so did the arrow glance off
+and recoil from the shield of Menelaus, who in his turn wounded
+the hand with which Helenus carried his bow; the spear went right
+through his hand and stuck in the bow itself, so that to his life
+he retreated under cover of his men, with his hand dragging by
+his side--for the spear weighed it down till Agenor drew it out
+and bound the hand carefully up in a woollen sling which his
+esquire had with him.
+</para>
+
+<para>
+Pisander then made straight at Menelaus--his evil destiny luring
+him on to his doom, for he was to fall in fight with you, O
+Menelaus. When the two were hard by one another the spear of the
+son of Atreus turned aside and he missed his aim; Pisander then
+struck the shield of brave Menelaus but could not pierce it, for
+the shield stayed the spear and broke the shaft; nevertheless he
+was glad and made sure of victory; forthwith, however, the son of
+Atreus drew his sword and sprang upon him. Pisander then seized
+the bronze battle-axe, with its long and polished handle of olive
+wood that hung by his side under his shield, and the two made at
+one another. Pisander struck the peak of Menelaus's crested
+helmet just under the crest itself, and Menelaus hit Pisander as
+he was coming towards him, on the forehead, just at the rise of
+his nose; the bones cracked and his two gore-bedrabbled eyes fell
+by his feet in the dust. He fell backwards to the ground, and
+Menelaus set his heel upon him, stripped him of his armour, and
+vaunted over him saying, "Even thus shall you Trojans leave the
+ships of the Achaeans, proud and insatiate of battle though you
+be, nor shall you lack any of the disgrace and shame which you
+have heaped upon myself. Cowardly she-wolves that you are, you
+feared not the anger of dread Jove, avenger of violated
+hospitality, who will one day destroy your city; you stole my
+wedded wife and wickedly carried off much treasure when you were
+her guest, and now you would fling fire upon our ships, and kill
+our heroes. A day will come when, rage as you may, you shall be
+stayed. O father Jove, you, who they say art above all, both gods
+and men, in wisdom, and from whom all things that befall us do
+proceed, how can you thus favour the Trojans--men so proud and
+overweening, that they are never tired of fighting? All things
+pall after a while--sleep, love, sweet song, and stately dance--
+still these are things of which a man would surely have his fill
+rather than of battle, whereas it is of battle that the Trojans
+are insatiate."
+</para>
+
+<para>
+So saying Menelaus stripped the blood-stained armour from the
+body of Pisander, and handed it over to his men; then he again
+ranged himself among those who were in the front of the fight.
+</para>
+
+<para>
+Harpalion son of King Pylaemenes then sprang upon him; he had
+come to fight at Troy along with his father, but he did not go
+home again. He struck the middle of Menelaus's shield with his
+spear but could not pierce it, and to save his life drew back
+under cover of his men, looking round him on every side lest he
+should be wounded. But Meriones aimed a bronze-tipped arrow at
+him as he was leaving the field, and hit him on the right
+buttock; the arrow pierced the bone through and through, and
+penetrated the bladder, so he sat down where he was and breathed
+his last in the arms of his comrades, stretched like a worm upon
+the ground and watering the earth with the blood that flowed from
+his wound. The brave Paphlagonians tended him with all due care;
+they raised him into his chariot, and bore him sadly off to the
+city of Troy; his father went also with him weeping bitterly, but
+there was no ransom that could bring his dead son to life again.
+</para>
+
+<para>
+Paris was deeply grieved by the death of Harpalion, who was his
+host when he went among the Paphlagonians; he aimed an arrow,
+therefore, in order to avenge him. Now there was a certain man
+named Euchenor, son of Polyidus the prophet, a brave man and
+wealthy, whose home was in Corinth. This Euchenor had set sail
+for Troy well knowing that it would be the death of him, for his
+good old father Polyidus had often told him that he must either
+stay at home and die of a terrible disease, or go with the
+Achaeans and perish at the hands of the Trojans; he chose,
+therefore, to avoid incurring the heavy fine the Achaeans would
+have laid upon him, and at the same time to escape the pain and
+suffering of disease. Paris now smote him on the jaw under his
+ear, whereon the life went out of him and he was enshrouded in
+the darkness of death.
+</para>
+
+<para>
+Thus then did they fight as it were a flaming fire. But Hector
+had not yet heard, and did not know that the Argives were making
+havoc of his men on the left wing of the battle, where the
+Achaeans ere long would have triumphed over them, so vigorously
+did Neptune cheer them on and help them. He therefore held on at
+the point where he had first forced his way through the gates and
+the wall, after breaking through the serried ranks of Danaan
+warriors. It was here that the ships of Ajax and Protesilaus were
+drawn up by the sea-shore; here the wall was at its lowest, and
+the fight both of man and horse raged most fiercely. The
+Boeotians and the Ionians with their long tunics, the Locrians,
+the men of Phthia, and the famous force of the Epeans could
+hardly stay Hector as he rushed on towards the ships, nor could
+they drive him from them, for he was as a wall of fire. The
+chosen men of the Athenians were in the van, led by Menestheus
+son of Peteos, with whom were also Pheidas, Stichius, and
+stalwart Bias; Meges son of Phyleus, Amphion, and Dracius
+commanded the Epeans, while Medon and staunch Podarces led the
+men of Phthia. Of these, Medon was bastard son to Oileus and
+brother of Ajax, but he lived in Phylace away from his own
+country, for he had killed the brother of his stepmother Eriopis,
+the wife of Oileus; the other, Podarces, was the son of Iphiclus,
+son of Phylacus. These two stood in the van of the Phthians, and
+defended the ships along with the Boeotians.
+</para>
+
+<para>
+Ajax son of Oileus, never for a moment left the side of Ajax, son
+of Telamon, but as two swart oxen both strain their utmost at the
+plough which they are drawing in a fallow field, and the sweat
+steams upwards from about the roots of their horns--nothing but
+the yoke divides them as they break up the ground till they reach
+the end of the field--even so did the two Ajaxes stand shoulder
+to shoulder by one another. Many and brave comrades followed the
+son of Telamon, to relieve him of his shield when he was overcome
+with sweat and toil, but the Locrians did not follow so close
+after the son of Oileus, for they could not hold their own in a
+hand-to-hand fight. They had no bronze helmets with plumes of
+horse-hair, neither had they shields nor ashen spears, but they
+had come to Troy armed with bows, and with slings of twisted wool
+from which they showered their missiles to break the ranks of the
+Trojans. The others, therefore, with their heavy armour bore the
+brunt of the fight with the Trojans and with Hector, while the
+Locrians shot from behind, under their cover; and thus the
+Trojans began to lose heart, for the arrows threw them into
+confusion.
+</para>
+
+<para>
+The Trojans would now have been driven in sorry plight from the
+ships and tents back to windy Ilius, had not Polydamas presently
+said to Hector, "Hector, there is no persuading you to take
+advice. Because heaven has so richly endowed you with the arts of
+war, you think that you must therefore excel others in counsel;
+but you cannot thus claim preeminence in all things. Heaven has
+made one man an excellent soldier; of another it has made a
+dancer or a singer and player on the lyre; while yet in another
+Jove has implanted a wise understanding of which men reap fruit
+to the saving of many, and he himself knows more about it than
+any one; therefore I will say what I think will be best. The
+fight has hemmed you in as with a circle of fire, and even now
+that the Trojans are within the wall some of them stand aloof in
+full armour, while others are fighting scattered and outnumbered
+near the ships. Draw back, therefore, and call your chieftains
+round you, that we may advise together whether to fall now upon
+the ships in the hope that heaven may vouchsafe us victory, or to
+beat a retreat while we can yet safely do so. I greatly fear that
+the Achaeans will pay us their debt of yesterday in full, for
+there is one abiding at their ships who is never weary of battle,
+and who will not hold aloof much longer."
+</para>
+
+<para>
+Thus spoke Polydamas, and his words pleased Hector well. He
+sprang in full armour from his chariot and said, "Polydamas,
+gather the chieftains here; I will go yonder into the fight, but
+will return at once when I have given them their orders."
+</para>
+
+<para>
+He then sped onward, towering like a snowy mountain, and with a
+loud cry flew through the ranks of the Trojans and their allies.
+When they heard his voice they all hastened to gather round
+Polydamas, the excellent son of Panthous, but Hector kept on
+among the foremost, looking everywhere to find Deiphobus and
+prince Helenus, Adamas son of Asius, and Asius son of Hyrtacus;
+living, indeed, and scatheless he could no longer find them, for
+the two last were lying by the sterns of the Achaean ships, slain
+by the Argives, while the others had been also stricken and
+wounded by them; but upon the left wing of the dread battle he
+found Alexandrus, husband of lovely Helen, cheering his men and
+urging them on to fight. He went up to him and upbraided him.
+"Paris," said he, "evil-hearted Paris, fair to see but woman-mad
+and false of tongue, where are Deiphobus and King Helenus? Where
+are Adamas son of Asius, and Asius son of Hyrtacus? Where too is
+Othryoneus? Ilius is undone and will now surely fall!"
+</para>
+
+<para>
+Alexandrus answered, "Hector, why find fault when there is no one
+to find fault with? I should hold aloof from battle on any day
+rather than this, for my mother bore me with nothing of the
+coward about me. From the moment when you set our men fighting
+about the ships we have been staying here and doing battle with
+the Danaans. Our comrades about whom you ask me are dead;
+Deiphobus and King Helenus alone have left the field, wounded
+both of them in the hand, but the son of Saturn saved them alive.
+Now, therefore, lead on where you would have us go, and we will
+follow with right goodwill; you shall not find us fail you in so
+far as our strength holds out, but no man can do more than in him
+lies, no matter how willing he may be."
+</para>
+
+<para>
+With these words he satisfied his brother, and the two went
+towards the part of the battle where the fight was thickest,
+about Cebriones, brave Polydamas, Phalces, Orthaeus, godlike
+Polyphetes, Palmys, Ascanius, and Morys son of Hippotion, who had
+come from fertile Ascania on the preceding day to relieve other
+troops. Then Jove urged them on to fight. They flew forth like
+the blasts of some fierce wind that strike earth in the van of a
+thunderstorm--they buffet the salt sea into an uproar; many and
+mighty are the great waves that come crashing in one after the
+other upon the shore with their arching heads all crested with
+foam--even so did rank behind rank of Trojans arrayed in gleaming
+armour follow their leaders onward. The way was led by Hector son
+of Priam, peer of murderous Mars, with his round shield before
+him--his shield of ox-hides covered with plates of bronze--and
+his gleaming helmet upon his temples. He kept stepping forward
+under cover of his shield in every direction, making trial of the
+ranks to see if they would give way before him, but he could not
+daunt the courage of the Achaeans. Ajax was the first to stride
+out and challenge him. "Sir," he cried, "draw near; why do you
+think thus vainly to dismay the Argives? We Achaeans are
+excellent soldiers, but the scourge of Jove has fallen heavily
+upon us. Your heart, forsooth, is set on destroying our ships,
+but we too have hands that can keep you at bay, and your own fair
+town shall be sooner taken and sacked by ourselves. The time is
+near when you shall pray Jove and all the gods in your flight,
+that your steeds may be swifter than hawks as they raise the dust
+on the plain and bear you back to your city."
+</para>
+
+<para>
+As he was thus speaking a bird flew by upon his right hand, and
+the host of the Achaeans shouted, for they took heart at the
+omen. But Hector answered, "Ajax, braggart and false of tongue,
+would that I were as sure of being son for evermore to
+aegis-bearing Jove, with Queen Juno for my mother, and of being
+held in like honour with Minerva and Apollo, as I am that this
+day is big with the destruction of the Achaeans; and you shall
+fall among them if you dare abide my spear; it shall rend your
+fair body and bid you glut our hounds and birds of prey with your
+fat and your flesh, as you fall by the ships of the Achaeans."
+</para>
+
+<para>
+With these words he led the way and the others followed after
+with a cry that rent the air, while the host shouted behind them.
+The Argives on their part raised a shout likewise, nor did they
+forget their prowess, but stood firm against the onslaught of the
+Trojan chieftains, and the cry from both the hosts rose up to
+heaven and to the brightness of Jove's presence.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK XIV</title>
+
+<para>
+NESTOR was sitting over his wine, but the cry of battle did not
+escape him, and he said to the son of Aesculapius, "What, noble
+Machaon, is the meaning of all this? The shouts of men fighting
+by our ships grow stronger and stronger; stay here, therefore,
+and sit over your wine, while fair Hecamede heats you a bath and
+washes the clotted blood from off you. I will go at once to the
+look-out station and see what it is all about."
+</para>
+
+<para>
+As he spoke he took up the shield of his son Thrasymedes that was
+lying in his tent, all gleaming with bronze, for Thrasymedes had
+taken his father's shield; he grasped his redoubtable bronze-shod
+spear, and as soon as he was outside saw the disastrous rout of
+the Achaeans who, now that their wall was overthrown, were flying
+pell-mell before the Trojans. As when there is a heavy swell upon
+the sea, but the waves are dumb--they keep their eyes on the
+watch for the quarter whence the fierce winds may spring upon
+them, but they stay where they are and set neither this way nor
+that, till some particular wind sweeps down from heaven to
+determine them--even so did the old man ponder whether to make
+for the crowd of Danaans, or go in search of Agamemnon. In the
+end he deemed it best to go to the son of Atreus; but meanwhile
+the hosts were fighting and killing one another, and the hard
+bronze rattled on their bodies, as they thrust at one another
+with their swords and spears.
+</para>
+
+<para>
+The wounded kings, the son of Tydeus, Ulysses, and Agamemnon son
+of Atreus, fell in Nestor as they were coming up from their
+ships--for theirs were drawn up some way from where the fighting
+was going on, being on the shore itself inasmuch as they had been
+beached first, while the wall had been built behind the
+hindermost. The stretch of the shore, wide though it was, did not
+afford room for all the ships, and the host was cramped for
+space, therefore they had placed the ships in rows one behind the
+other, and had filled the whole opening of the bay between the
+two points that formed it. The kings, leaning on their spears,
+were coming out to survey the fight, being in great anxiety, and
+when old Nestor met them they were filled with dismay. Then King
+Agamemnon said to him, "Nestor son of Neleus, honour to the
+Achaean name, why have you left the battle to come hither? I fear
+that what dread Hector said will come true, when he vaunted among
+the Trojans saying that he would not return to Ilius till he had
+fired our ships and killed us; this is what he said, and now it
+is all coming true. Alas! others of the Achaeans, like Achilles,
+are in anger with me that they refuse to fight by the sterns of
+our ships."
+</para>
+
+<para>
+Then Nestor knight of Gerene, answered, "It is indeed as you say;
+it is all coming true at this moment, and even Jove who thunders
+from on high cannot prevent it. Fallen is the wall on which we
+relied as an impregnable bulwark both for us and our fleet. The
+Trojans are fighting stubbornly and without ceasing at the ships;
+look where you may you cannot see from what quarter the rout of
+the Achaeans is coming; they are being killed in a confused mass
+and the battle-cry ascends to heaven; let us think, if counsel
+can be of any use, what we had better do; but I do not advise our
+going into battle ourselves, for a man cannot fight when he is
+wounded."
+</para>
+
+<para>
+And King Agamemnon answered, "Nestor, if the Trojans are indeed
+fighting at the rear of our ships, and neither the wall nor the
+trench has served us--over which the Danaans toiled so hard, and
+which they deemed would be an impregnable bulwark both for us and
+our fleet--I see it must be the will of Jove that the Achaeans
+should perish ingloriously here, far from Argos. I knew when Jove
+was willing to defend us, and I know now that he is raising the
+Trojans to like honour with the gods, while us, on the other
+hand, he bas bound hand and foot. Now, therefore, let us all do
+as I say; let us bring down the ships that are on the beach and
+draw them into the water; let us make them fast to their
+mooring-stones a little way out, against the fall of night--if
+even by night the Trojans will desist from fighting; we may then
+draw down the rest of the fleet. There is nothing wrong in flying
+ruin even by night. It is better for a man that he should fly and
+be saved than be caught and killed."
+</para>
+
+<para>
+Ulysses looked fiercely at him and said, "Son of Atreus, what are
+you talking about? Wretch, you should have commanded some other
+and baser army, and not been ruler over us to whom Jove has
+allotted a life of hard fighting from youth to old age, till we
+every one of us perish. Is it thus that you would quit the city
+of Troy, to win which we have suffered so much hardship? Hold
+your peace, lest some other of the Achaeans hear you say what no
+man who knows how to give good counsel, no king over so great a
+host as that of the Argives should ever have let fall from his
+lips. I despise your judgement utterly for what you have been
+saying. Would you, then, have us draw down our ships into the
+water while the battle is raging, and thus play further into the
+hands of the conquering Trojans? It would be ruin; the Achaeans
+will not go on fighting when they see the ships being drawn into
+the water, but will cease attacking and keep turning their eyes
+towards them; your counsel, therefore, sir captain, would be our
+destruction."
+</para>
+
+<para>
+Agamemnon answered, "Ulysses, your rebuke has stung me to the
+heart. I am not, however, ordering the Achaeans to draw their
+ships into the sea whether they will or no. Someone, it may be,
+old or young, can offer us better counsel which I shall rejoice
+to hear."
+</para>
+
+<para>
+Then said Diomed, "Such an one is at hand; he is not far to seek,
+if you will listen to me and not resent my speaking though I am
+younger than any of you. I am by lineage son to a noble sire,
+Tydeus, who lies buried at Thebes. For Portheus had three noble
+sons, two of whom, Agrius and Melas, abode in Pleuron and rocky
+Calydon. The third was the knight Oeneus, my father's father, and
+he was the most valiant of them all. Oeneus remained in his own
+country, but my father (as Jove and the other gods ordained it)
+migrated to Argos. He married into the family of Adrastus, and
+his house was one of great abundance, for he had large estates of
+rich corn-growing land, with much orchard ground as well, and he
+had many sheep; moreover he excelled all the Argives in the use
+of the spear. You must yourselves have heard whether these things
+are true or no; therefore when I say well despise not my words as
+though I were a coward or of ignoble birth. I say, then, let us
+go to the fight as we needs must, wounded though we be. When
+there, we may keep out of the battle and beyond the range of the
+spears lest we get fresh wounds in addition to what we have
+already, but we can spur on others, who have been indulging their
+spleen and holding aloof from battle hitherto."
+</para>
+
+<para>
+Thus did he speak; whereon they did even as he had said and set
+out, King Agamemnon leading the way.
+</para>
+
+<para>
+Meanwhile Neptune had kept no blind look-out, and came up to them
+in the semblance of an old man. He took Agamemnon's right hand in
+his own and said, "Son of Atreus, I take it Achilles is glad now
+that he sees the Achaeans routed and slain, for he is utterly
+without remorse--may he come to a bad end and heaven confound
+him. As for yourself, the blessed gods are not yet so bitterly
+angry with you but that the princes and counsellors of the
+Trojans shall again raise the dust upon the plain, and you shall
+see them flying from the ships and tents towards their city."
+</para>
+
+<para>
+With this he raised a mighty cry of battle, and sped forward to
+the plain. The voice that came from his deep chest was as that of
+nine or ten thousand men when they are shouting in the thick of a
+fight, and it put fresh courage into the hearts of the Achaeans
+to wage war and do battle without ceasing.
+</para>
+
+<para>
+Juno of the golden throne looked down as she stood upon a peak of
+Olympus and her heart was gladdened at the sight of him who was
+at once her brother and her brother-in-law, hurrying hither and
+thither amid the fighting. Then she turned her eyes to Jove as he
+sat on the topmost crests of many-fountained Ida, and loathed
+him. She set herself to think how she might hoodwink him, and in
+the end she deemed that it would be best for her to go to Ida and
+array herself in rich attire, in the hope that Jove might become
+enamoured of her, and wish to embrace her. While he was thus
+engaged a sweet and careless sleep might be made to steal over
+his eyes and senses.
+</para>
+
+<para>
+She went, therefore, to the room which her son Vulcan had made
+her, and the doors of which he had cunningly fastened by means of
+a secret key so that no other god could open them. Here she
+entered and closed the doors behind her. She cleansed all the
+dirt from her fair body with ambrosia, then she anointed herself
+with olive oil, ambrosial, very soft, and scented specially for
+herself--if it were so much as shaken in the bronze-floored house
+of Jove, the scent pervaded the universe of heaven and earth.
+With this she anointed her delicate skin, and then she plaited
+the fair ambrosial locks that flowed in a stream of golden
+tresses from her immortal head. She put on the wondrous robe
+which Minerva had worked for her with consummate art, and had
+embroidered with manifold devices; she fastened it about her
+bosom with golden clasps, and she girded herself with a girdle
+that had a hundred tassels: then she fastened her earrings, three
+brilliant pendants that glistened most beautifully, through the
+pierced lobes of her ears, and threw a lovely new veil over her
+head. She bound her sandals on to her feet, and when she had
+arrayed herself perfectly to her satisfaction, she left her room
+and called Venus to come aside and speak to her. "My dear child,"
+said she, "will you do what I am going to ask of you, or will
+refuse me because you are angry at my being on the Danaan side,
+while you are on the Trojan?"
+</para>
+
+<para>
+Jove's daughter Venus answered, "Juno, august queen of goddesses,
+daughter of mighty Saturn, say what you want, and I will do it
+for you at once, if I can, and if it can be done at all."
+</para>
+
+<para>
+Then Juno told her a lying tale and said, "I want you to endow me
+with some of those fascinating charms, the spells of which bring
+all things mortal and immortal to your feet. I am going to the
+world's end to visit Oceanus (from whom all we gods proceed) and
+mother Tethys: they received me in their house, took care of me,
+and brought me up, having taken me over from Rhaea when Jove
+imprisoned great Saturn in the depths that are under earth and
+sea. I must go and see them that I may make peace between them;
+they have been quarrelling, and are so angry that they have not
+slept with one another this long while; if I can bring them round
+and restore them to one another's embraces, they will be grateful
+to me and love me for ever afterwards."
+</para>
+
+<para>
+Thereon laughter-loving Venus said, "I cannot and must not refuse
+you, for you sleep in the arms of Jove who is our king."
+</para>
+
+<para>
+As she spoke she loosed from her bosom the curiously embroidered
+girdle into which all her charms had been wrought--love, desire,
+and that sweet flattery which steals the judgement even of the
+most prudent. She gave the girdle to Juno and said, "Take this
+girdle wherein all my charms reside and lay it in your bosom. If
+you will wear it I promise you that your errand, be it what it
+may, will not be bootless."
+</para>
+
+<para>
+When she heard this Juno smiled, and still smiling she laid the
+girdle in her bosom.
+</para>
+
+<para>
+Venus now went back into the house of Jove, while Juno darted
+down from the summits of Olympus. She passed over Pieria and fair
+Emathia, and went on and on till she came to the snowy ranges of
+the Thracian horsemen, over whose topmost crests she sped without
+ever setting foot to ground. When she came to Athos she went on
+over the, waves of the sea till she reached Lemnos, the city of
+noble Thoas. There she met Sleep, own brother to Death, and
+caught him by the hand, saying, "Sleep, you who lord it alike
+over mortals and immortals, if you ever did me a service in times
+past, do one for me now, and I shall be grateful to you ever
+after. Close Jove's keen eyes for me in slumber while I hold him
+clasped in my embrace, and I will give you a beautiful golden
+seat, that can never fall to pieces; my clubfooted son Vulcan
+shall make it for you, and he shall give it a footstool for you
+to rest your fair feet upon when you are at table."
+</para>
+
+<para>
+Then Sleep answered, "Juno, great queen of goddesses, daughter of
+mighty Saturn, I would lull any other of the gods to sleep
+without compunction, not even excepting the waters of Oceanus
+from whom all of them proceed, but I dare not go near Jove, nor
+send him to sleep unless he bids me. I have had one lesson
+already through doing what you asked me, on the day when Jove's
+mighty son Hercules set sail from Ilius after having sacked the
+city of the Trojans. At your bidding I suffused my sweet self
+over the mind of aegis-bearing Jove, and laid him to rest;
+meanwhile you hatched a plot against Hercules, and set the blasts
+of the angry winds beating upon the sea, till you took him to the
+goodly city of Cos, away from all his friends. Jove was furious
+when he awoke, and began hurling the gods about all over the
+house; he was looking more particularly for myself, and would
+have flung me down through space into the sea where I should
+never have been heard of any more, had not Night who cows both
+men and gods protected me. I fled to her and Jove left off
+looking for me in spite of his being so angry, for he did not
+dare do anything to displease Night. And now you are again asking
+me to do something on which I cannot venture."
+</para>
+
+<para>
+And Juno said, "Sleep, why do you take such notions as those into
+your head? Do you think Jove will be as anxious to help the
+Trojans, as he was about his own son? Come, I will marry you to
+one of the youngest of the Graces, and she shall be your own--
+Pasithea, whom you have always wanted to marry."
+</para>
+
+<para>
+Sleep was pleased when he heard this, and answered, "Then swear
+it to me by the dread waters of the river Styx; lay one hand on
+the bounteous earth, and the other on the sheen of the sea, so
+that all the gods who dwell down below with Saturn may be our
+witnesses, and see that you really do give me one of the youngest
+of the Graces--Pasithea, whom I have always wanted to marry."
+</para>
+
+<para>
+Juno did as he had said. She swore, and invoked all the gods of
+the nether world, who are called Titans, to witness. When she had
+completed her oath, the two enshrouded themselves in a thick mist
+and sped lightly forward, leaving Lemnos and Imbrus behind them.
+Presently they reached many-fountained Ida, mother of wild
+beasts, and Lectum where they left the sea to go on by land, and
+the tops of the trees of the forest soughed under the going of
+their feet. Here Sleep halted, and ere Jove caught sight of him
+he climbed a lofty pine-tree--the tallest that reared its head
+towards heaven on all Ida. He hid himself behind the branches and
+sat there in the semblance of the sweet-singing bird that haunts
+the mountains and is called Chalcis by the gods, but men call it
+Cymindis. Juno then went to Gargarus, the topmost peak of Ida,
+and Jove, driver of the clouds, set eyes upon her. As soon as he
+did so he became inflamed with the same passionate desire for her
+that he had felt when they had first enjoyed each other's
+embraces, and slept with one another without their dear parents
+knowing anything about it. He went up to her and said, "What do
+you want that you have come hither from Olympus--and that too
+with neither chariot nor horses to convey you?"
+</para>
+
+<para>
+Then Juno told him a lying tale and said, "I am going to the
+world's end, to visit Oceanus, from whom all we gods proceed, and
+mother Tethys; they received me into their house, took care of
+me, and brought me up. I must go and see them that I may make
+peace between them: they have been quarrelling, and are so angry
+that they have not slept with one another this long time. The
+horses that will take me over land and sea are stationed on the
+lowermost spurs of many-fountained Ida, and I have come here from
+Olympus on purpose to consult you. I was afraid you might be
+angry with me later on, if I went to the house of Oceanus without
+letting you know."
+</para>
+
+<para>
+And Jove said, "Juno, you can choose some other time for paying
+your visit to Oceanus--for the present let us devote ourselves to
+love and to the enjoyment of one another. Never yet have I been
+so overpowered by passion neither for goddess nor mortal woman as
+I am at this moment for yourself--not even when I was in love
+with the wife of Ixion who bore me Pirithous, peer of gods in
+counsel, nor yet with Danae the daintily-ancled daughter of
+Acrisius, who bore me the famed hero Perseus. Then there was the
+daughter of Phoenix, who bore me Minos and Rhadamanthus: there
+was Semele, and Alcmena in Thebes by whom I begot my lion-hearted
+son Hercules, while Semele became mother to Bacchus the comforter
+of mankind. There was queen Ceres again, and lovely Leto, and
+yourself--but with none of these was I ever so much enamoured as
+I now am with you."
+</para>
+
+<para>
+Juno again answered him with a lying tale. "Most dread son of
+Saturn," she exclaimed, "what are you talking about? Would you
+have us enjoy one another here on the top of Mount Ida, where
+everything can be seen? What if one of the ever-living gods
+should see us sleeping together, and tell the others? It would be
+such a scandal that when I had risen from your embraces I could
+never show myself inside your house again; but if you are so
+minded, there is a room which your son Vulcan has made me, and he
+has given it good strong doors; if you would so have it, let us
+go thither and lie down."
+</para>
+
+<para>
+And Jove answered, "Juno, you need not be afraid that either god
+or man will see you, for I will enshroud both of us in such a
+dense golden cloud, that the very sun for all his bright piercing
+beams shall not see through it."
+</para>
+
+<para>
+With this the son of Saturn caught his wife in his embrace;
+whereon the earth sprouted them a cushion of young grass, with
+dew-bespangled lotus, crocus, and hyacinth, so soft and thick
+that it raised them well above the ground. Here they laid
+themselves down and overhead they were covered by a fair cloud of
+gold, from which there fell glittering dew-drops.
+</para>
+
+<para>
+Thus, then, did the sire of all things repose peacefully on the
+crest of Ida, overcome at once by sleep and love, and he held his
+spouse in his arms. Meanwhile Sleep made off to the ships of the
+Achaeans, to tell earth-encircling Neptune, lord of the
+earthquake. When he had found him he said, "Now, Neptune, you can
+help the Danaans with a will, and give them victory though it be
+only for a short time while Jove is still sleeping. I have sent
+him into a sweet slumber, and Juno has beguiled him into going to
+bed with her."
+</para>
+
+<para>
+Sleep now departed and went his ways to and fro among mankind,
+leaving Neptune more eager than ever to help the Danaans. He
+darted forward among the first ranks and shouted saying,
+"Argives, shall we let Hector son of Priam have the triumph of
+taking our ships and covering himself with glory? This is what he
+says that he shall now do, seeing that Achilles is still in
+dudgeon at his ship; we shall get on very well without him if we
+keep each other in heart and stand by one another. Now,
+therefore, let us all do as I say. Let us each take the best and
+largest shield we can lay hold of, put on our helmets, and sally
+forth with our longest spears in our hands; I will lead you on,
+and Hector son of Priam, rage as he may, will not dare to hold
+out against us. If any good staunch soldier has only a small
+shield, let him hand it over to a worse man, and take a larger
+one for himself."
+</para>
+
+<para>
+Thus did he speak, and they did even as he had said. The son of
+Tydeus, Ulysses, and Agamemnon, wounded though they were, set the
+others in array, and went about everywhere effecting the
+exchanges of armour; the most valiant took the best armour, and
+gave the worse to the worse man. When they had donned their
+bronze armour they marched on with Neptune at their head. In his
+strong hand he grasped his terrible sword, keen of edge and
+flashing like lightning; woe to him who comes across it in the
+day of battle; all men quake for fear and keep away from it.
+</para>
+
+<para>
+Hector on the other side set the Trojans in array. Thereon
+Neptune and Hector waged fierce war on one another--Hector on the
+Trojan and Neptune on the Argive side. Mighty was the uproar as
+the two forces met; the sea came rolling in towards the ships and
+tents of the Achaeans, but waves do not thunder on the shore more
+loudly when driven before the blast of Boreas, nor do the flames
+of a forest fire roar more fiercely when it is well alight upon
+the mountains, nor does the wind bellow with ruder music as it
+tears on through the tops of when it is blowing its hardest, than
+the terrible shout which the Trojans and Achaeans raised as they
+sprang upon one another.
+</para>
+
+<para>
+Hector first aimed his spear at Ajax, who was turned full towards
+him, nor did he miss his aim. The spear struck him where two
+bands passed over his chest--the band of his shield and that of
+his silver-studded sword--and these protected his body. Hector
+was angry that his spear should have been hurled in vain, and
+withdrew under cover of his men. As he was thus retreating, Ajax
+son of Telamon, struck him with a stone, of which there were many
+lying about under the men's feet as they fought--brought there to
+give support to the ships' sides as they lay on the shore. Ajax
+caught up one of them and struck Hector above the rim of his
+shield close to his neck; the blow made him spin round like a top
+and reel in all directions. As an oak falls headlong when
+uprooted by the lightning flash of father Jove, and there is a
+terrible smell of brimstone--no man can help being dismayed if he
+is standing near it, for a thunderbolt is a very awful thing--
+even so did Hector fall to earth and bite the dust. His spear
+fell from his hand, but his shield and helmet were made fast
+about his body, and his bronze armour rang about him.
+</para>
+
+<para>
+The sons of the Achaeans came running with a loud cry towards
+him, hoping to drag him away, and they showered their darts on
+the Trojans, but none of them could wound him before he was
+surrounded and covered by the princes Polydamas, Aeneas, Agenor,
+Sarpedon captain of the Lycians, and noble Glaucus. Of the
+others, too, there was not one who was unmindful of him, and they
+held their round shields over him to cover him. His comrades then
+lifted him off the ground and bore him away from the battle to
+the place where his horses stood waiting for him at the rear of
+the fight with their driver and the chariot; these then took him
+towards the city groaning and in great pain. When they reached
+the ford of the fair stream of Xanthus, begotten of Immortal
+Jove, they took him from off his chariot and laid him down on the
+ground; they poured water over him, and as they did so he
+breathed again and opened his eyes. Then kneeling on his knees he
+vomited blood, but soon fell back on to the ground, and his eyes
+were again closed in darkness for he was still stunned by the
+blow.
+</para>
+
+<para>
+When the Argives saw Hector leaving the field, they took heart
+and set upon the Trojans yet more furiously. Ajax fleet son of
+Oileus began by springing on Satnius son of Enops, and wounding
+him with his spear: a fair naiad nymph had borne him to Enops as
+he was herding cattle by the banks of the river Satnioeis. The
+son of Oileus came up to him and struck him in the flank so that
+he fell, and a fierce fight between Trojans and Danaans raged
+round his body. Polydamas son of Panthous drew near to avenge
+him, and wounded Prothoenor son of Areilycus on the right
+shoulder; the terrible spear went right through his shoulder, and
+he clutched the earth as he fell in the dust. Polydamas vaunted
+loudly over him saying, "Again I take it that the spear has not
+sped in vain from the strong hand of the son of Panthous; an
+Argive has caught it in his body, and it will serve him for a
+staff as he goes down into the house of Hades."
+</para>
+
+<para>
+The Argives were maddened by this boasting. Ajax son of Telamon
+was more angry than any, for the man had fallen close beside him;
+so he aimed at Polydamas as he was retreating, but Polydamas
+saved himself by swerving aside and the spear struck Archelochus
+son of Antenor, for heaven counselled his destruction; it struck
+him where the head springs from the neck at the top joint of the
+spine, and severed both the tendons at the back of the head. His
+head, mouth, and nostrils reached the ground long before his legs
+and knees could do so, and Ajax shouted to Polydamas saying,
+"Think, Polydamas, and tell me truly whether this man is not as
+well worth killing as Prothoenor was: he seems rich, and of rich
+family, a brother, it may be, or son of the knight Antenor, for
+he is very like him."
+</para>
+
+<para>
+But he knew well who it was, and the Trojans were greatly
+angered. Acamas then bestrode his brother's body and wounded
+Promachus the Boeotian with his spear, for he was trying to drag
+his brother's body away. Acamas vaunted loudly over him saying,
+"Argive archers, braggarts that you are, toil and suffering shall
+not be for us only, but some of you too shall fall here as well
+as ourselves. See how Promachus now sleeps, vanquished by my
+spear; payment for my brother's blood has not been long delayed;
+a man, therefore, may well be thankful if he leaves a kinsman in
+his house behind him to avenge his fall."
+</para>
+
+<para>
+His taunts infuriated the Argives, and Peneleos was more enraged
+than any of them. He sprang towards Acamas, but Acamas did not
+stand his ground, and he killed Ilioneus son of the rich
+flock-master Phorbas, whom Mercury had favoured and endowed with
+greater wealth than any other of the Trojans. Ilioneus was his
+only son, and Peneleos now wounded him in the eye under his
+eyebrows, tearing the eye-ball from its socket: the spear went
+right through the eye into the nape of the neck, and he fell,
+stretching out both hands before him. Peneleos then drew his
+sword and smote him on the neck, so that both head and helmet
+came tumbling down to the ground with the spear still sticking in
+the eye; he then held up the head, as though it had been a
+poppy-head, and showed it to the Trojans, vaunting over them as
+he did so. "Trojans," he cried, "bid the father and mother of
+noble Ilioneus make moan for him in their house, for the wife
+also of Promachus son of Alegenor will never be gladdened by the
+coming of her dear husband--when we Argives return with our ships
+from Troy."
+</para>
+
+<para>
+As he spoke fear fell upon them, and every man looked round about
+to see whither he might fly for safety.
+</para>
+
+<para>
+Tell me now, O Muses that dwell on Olympus, who was the first of
+the Argives to bear away blood-stained spoils after Neptune lord
+of the earthquake had turned the fortune of war. Ajax son of
+Telamon was first to wound Hyrtius son of Gyrtius, captain of the
+staunch Mysians. Antilochus killed Phalces and Mermerus, while
+Meriones slew Morys and Hippotion, Teucer also killed Prothoon
+and Periphetes. The son of Atreus then wounded Hyperenor shepherd
+of his people, in the flank, and the bronze point made his
+entrails gush out as it tore in among them; on this his life came
+hurrying out of him at the place where he had been wounded, and
+his eyes were closed in darkness. Ajax son of Oileus killed more
+than any other, for there was no man so fleet as he to pursue
+flying foes when Jove had spread panic among them.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK XV</title>
+
+<para>
+BUT when their flight had taken them past the trench and the set
+stakes, and many had fallen by the hands of the Danaans, the
+Trojans made a halt on reaching their chariots, routed and pale
+with fear. Jove now woke on the crests of Ida, where he was lying
+with golden-throned Juno by his side, and starting to his feet he
+saw the Trojans and Achaeans, the one thrown into confusion, and
+the others driving them pell-mell before them with King Neptune
+in their midst. He saw Hector lying on the ground with his
+comrades gathered round him, gasping for breath, wandering in
+mind and vomiting blood, for it was not the feeblest of the
+Achaeans who struck him.
+</para>
+
+<para>
+The sire of gods and men had pity on him, and looked fiercely on
+Juno. "I see, Juno," said he, "you mischief-making trickster,
+that your cunning has stayed Hector from fighting and has caused
+the rout of his host. I am in half a mind to thrash you, in which
+case you will be the first to reap the fruits of your scurvy
+knavery. Do you not remember how once upon a time I had you
+hanged? I fastened two anvils on to your feet, and bound your
+hands in a chain of gold which none might break, and you hung in
+mid-air among the clouds. All the gods in Olympus were in a fury,
+but they could not reach you to set you free; when I caught any
+one of them I gripped him and hurled him from the heavenly
+threshold till he came fainting down to earth; yet even this did
+not relieve my mind from the incessant anxiety which I felt about
+noble Hercules whom you and Boreas had spitefully conveyed beyond
+the seas to Cos, after suborning the tempests; but I rescued him,
+and notwithstanding all his mighty labours I brought him back
+again to Argos. I would remind you of this that you may learn to
+leave off being so deceitful, and discover how much you are
+likely to gain by the embraces out of which you have come here to
+trick me."
+</para>
+
+<para>
+Juno trembled as he spoke, and said, "May heaven above and earth
+below be my witnesses, with the waters of the river Styx--and
+this is the most solemn oath that a blessed god can take--nay, I
+swear also by your own almighty head and by our bridal bed--
+things over which I could never possibly perjure myself--that
+Neptune is not punishing Hector and the Trojans and helping the
+Achaeans through any doing of mine; it is all of his own mere
+motion because he was sorry to see the Achaeans hard pressed at
+their ships: if I were advising him, I should tell him to do as
+you bid him."
+</para>
+
+<para>
+The sire of gods and men smiled and answered, "If you, Juno, were
+always to support me when we sit in council of the gods, Neptune,
+like it or no, would soon come round to your and my way of
+thinking. If, then, you are speaking the truth and mean what you
+say, go among the rank and file of the gods, and tell Iris and
+Apollo lord of the bow, that I want them--Iris, that she may go
+to the Achaean host and tell Neptune to leave off fighting and go
+home, and Apollo, that he may send Hector again into battle and
+give him fresh strength; he will thus forget his present
+sufferings, and drive the Achaeans back in confusion till they
+fall among the ships of Achilles son of Peleus. Achilles will
+then send his comrade Patroclus into battle, and Hector will kill
+him in front of Ilius after he has slain many warriors, and among
+them my own noble son Sarpedon. Achilles will kill Hector to
+avenge Patroclus, and from that time I will bring it about that
+the Achaeans shall persistently drive the Trojans back till they
+fulfil the counsels of Minerva and take Ilius. But I will not
+stay my anger, nor permit any god to help the Danaans till I have
+accomplished the desire of the son of Peleus, according to the
+promise I made by bowing my head on the day when Thetis touched
+my knees and besought me to give him honour."
+</para>
+
+<para>
+Juno heeded his words and went from the heights of Ida to great
+Olympus. Swift as the thought of one whose fancy carries him over
+vast continents, and he says to himself, "Now I will be here, or
+there," and he would have all manner of things--even so swiftly
+did Juno wing her way till she came to high Olympus and went in
+among the gods who were gathered in the house of Jove. When they
+saw her they all of them came up to her, and held out their cups
+to her by way of greeting. She let the others be, but took the
+cup offered her by lovely Themis, who was first to come running
+up to her. "Juno," said she, "why are you here? And you seem
+troubled--has your husband the son of Saturn been frightening
+you?"
+</para>
+
+<para>
+And Juno answered, "Themis, do not ask me about it. You know what
+a proud and cruel disposition my husband has. Lead the gods to
+table, where you and all the immortals can hear the wicked
+designs which he has avowed. Many a one, mortal and immortal,
+will be angered by them, however peaceably he may be feasting
+now."
+</para>
+
+<para>
+On this Juno sat down, and the gods were troubled throughout the
+house of Jove. Laughter sat on her lips but her brow was furrowed
+with care, and she spoke up in a rage. "Fools that we are," she
+cried, "to be thus madly angry with Jove; we keep on wanting to
+go up to him and stay him by force or by persuasion, but he sits
+aloof and cares for nobody, for he knows that he is much stronger
+than any other of the immortals. Make the best, therefore, of
+whatever ills he may choose to send each one of you; Mars, I take
+it, has had a taste of them already, for his son Ascalaphus has
+fallen in battle--the man whom of all others he loved most dearly
+and whose father he owns himself to be."
+</para>
+
+<para>
+When he heard this Mars smote his two sturdy thighs with the flat
+of his hands, and said in anger, "Do not blame me, you gods that
+dwell in heaven, if I go to the ships of the Achaeans and avenge
+the death of my son, even though it end in my being struck by
+Jove's lightning and lying in blood and dust among the corpses."
+</para>
+
+<para>
+As he spoke he gave orders to yoke his horses Panic and Rout,
+while he put on his armour. On this, Jove would have been roused
+to still more fierce and implacable enmity against the other
+immortals, had not Minerva, alarmed for the safety of the gods,
+sprung from her seat and hurried outside. She tore the helmet
+from his head and the shield from his shoulders, and she took the
+bronze spear from his strong hand and set it on one side; then
+she said to Mars, "Madman, you are undone; you have ears that
+hear not, or you have lost all judgement and understanding; have
+you not heard what Juno has said on coming straight from the
+presence of Olympian Jove? Do you wish to go through all kinds of
+suffering before you are brought back sick and sorry to Olympus,
+after having caused infinite mischief to all us others? Jove
+would instantly leave the Trojans and Achaeans to themselves; he
+would come to Olympus to punish us, and would grip us up one
+after another, guilty or not guilty. Therefore lay aside your
+anger for the death of your son; better men than he have either
+been killed already or will fall hereafter, and one cannot
+protect every one's whole family."
+</para>
+
+<para>
+With these words she took Mars back to his seat. Meanwhile Juno
+called Apollo outside, with Iris the messenger of the gods.
+"Jove," she said to them, "desires you to go to him at once on
+Mt. Ida; when you have seen him you are to do as he may then bid
+you."
+</para>
+
+<para>
+Thereon Juno left them and resumed her seat inside, while Iris
+and Apollo made all haste on their way. When they reached
+many-fountained Ida, mother of wild beasts, they found Jove
+seated on topmost Gargarus with a fragrant cloud encircling his
+head as with a diadem. They stood before his presence, and he was
+pleased with them for having been so quick in obeying the orders
+his wife had given them.
+</para>
+
+<para>
+He spoke to Iris first. "Go," said he, "fleet Iris, tell King
+Neptune what I now bid you--and tell him true. Bid him leave off
+fighting, and either join the company of the gods, or go down
+into the sea. If he takes no heed and disobeys me, let him
+consider well whether he is strong enough to hold his own against
+me if I attack him. I am older and much stronger than he is; yet
+he is not afraid to set himself up as on a level with myself, of
+whom all the other gods stand in awe."
+</para>
+
+<para>
+Iris, fleet as the wind, obeyed him, and as the cold hail or
+snowflakes that fly from out the clouds before the blast of
+Boreas, even so did she wing her way till she came close up to
+the great shaker of the earth. Then she said, "I have come, O
+dark-haired king that holds the world in his embrace, to bring
+you a message from Jove. He bids you leave off fighting, and
+either join the company of the gods or go down into the sea; if,
+however, you take no heed and disobey him, he says he will come
+down here and fight you. He would have you keep out of his reach,
+for he is older and much stronger than you are, and yet you are
+not afraid to set yourself up as on a level with himself, of whom
+all the other gods stand in awe."
+</para>
+
+<para>
+Neptune was very angry and said, "Great heavens! strong as Jove
+may be, he has said more than he can do if he has threatened
+violence against me, who am of like honour with himself. We were
+three brothers whom Rhea bore to Saturn--Jove, myself, and Hades
+who rules the world below. Heaven and earth were divided into
+three parts, and each of us was to have an equal share. When we
+cast lots, it fell to me to have my dwelling in the sea for
+evermore; Hades took the darkness of the realms under the earth,
+while air and sky and clouds were the portion that fell to Jove;
+but earth and great Olympus are the common property of all.
+Therefore I will not walk as Jove would have me. For all his
+strength, let him keep to his own third share and be contented
+without threatening to lay hands upon me as though I were nobody.
+Let him keep his bragging talk for his own sons and daughters,
+who must perforce obey him."
+</para>
+
+<para>
+Iris fleet as the wind then answered, "Am I really, Neptune, to
+take this daring and unyielding message to Jove, or will you
+reconsider your answer? Sensible people are open to argument, and
+you know that the Erinyes always range themselves on the side of
+the older person."
+</para>
+
+<para>
+Neptune answered, "Goddess Iris, your words have been spoken in
+season. It is well when a messenger shows so much discretion.
+Nevertheless it cuts me to the very heart that any one should
+rebuke so angrily another who is his own peer, and of like empire
+with himself. Now, however, I will give way in spite of my
+displeasure; furthermore let me tell you, and I mean what I say--
+if contrary to the desire of myself, Minerva driver of the spoil,
+Juno, Mercury, and King Vulcan, Jove spares steep Ilius, and will
+not let the Achaeans have the great triumph of sacking it, let
+him understand that he will incur our implacable resentment."
+</para>
+
+<para>
+Neptune now left the field to go down under the sea, and sorely
+did the Achaeans miss him. Then Jove said to Apollo, "Go, dear
+Phoebus, to Hector, for Neptune who holds the earth in his
+embrace has now gone down under the sea to avoid the severity of
+my displeasure. Had he not done so those gods who are below with
+Saturn would have come to hear of the fight between us. It is
+better for both of us that he should have curbed his anger and
+kept out of my reach, for I should have had much trouble with
+him. Take, then, your tasselled aegis, and shake it furiously, so
+as to set the Achaean heroes in a panic; take, moreover, brave
+Hector, O Far-Darter, into your own care, and rouse him to deeds
+of daring, till the Achaeans are sent flying back to their ships
+and to the Hellespont. From that point I will think it well over,
+how the Achaeans may have a respite from their troubles."
+</para>
+
+<para>
+Apollo obeyed his father's saying, and left the crests of Ida,
+flying like a falcon, bane of doves and swiftest of all birds. He
+found Hector no longer lying upon the ground, but sitting up, for
+he had just come to himself again. He knew those who were about
+him, and the sweat and hard breathing had left him from the
+moment when the will of aegis-bearing Jove had revived him.
+Apollo stood beside him and said, "Hector son of Priam, why are
+you so faint, and why are you here away from the others? Has any
+mishap befallen you?"
+</para>
+
+<para>
+Hector in a weak voice answered, "And which, kind sir, of the
+gods are you, who now ask me thus? Do you not know that Ajax
+struck me on the chest with a stone as I was killing his comrades
+at the ships of the Achaeans, and compelled me to leave off
+fighting? I made sure that this very day I should breathe my last
+and go down into the house of Hades."
+</para>
+
+<para>
+Then King Apollo said to him, "Take heart; the son of Saturn has
+sent you a mighty helper from Ida to stand by you and defend you,
+even me, Phoebus Apollo of the golden sword, who have been
+guardian hitherto not only of yourself but of your city. Now,
+therefore, order your horsemen to drive their chariots to the
+ships in great multitudes. I will go before your horses to smooth
+the way for them, and will turn the Achaeans in flight."
+</para>
+
+<para>
+As he spoke he infused great strength into the shepherd of his
+people. And as a horse, stabled and full-fed, breaks loose and
+gallops gloriously over the plain to the place where he is wont
+to take his bath in the river--he tosses his head, and his mane
+streams over his shoulders as in all the pride of his strength he
+flies full speed to the pastures where the mares are feeding--
+even so Hector, when he heard what the god said, urged his
+horsemen on, and sped forward as fast as his limbs could take
+him. As country peasants set their hounds on to a homed stag or
+wild goat--he has taken shelter under rock or thicket, and they
+cannot find him, but, lo, a bearded lion whom their shouts have
+roused stands in their path, and they are in no further humour
+for the chase--even so the Achaeans were still charging on in a
+body, using their swords and spears pointed at both ends, but
+when they saw Hector going about among his men they were afraid,
+and their hearts fell down into their feet.
+</para>
+
+<para>
+Then spoke Thoas son of Andraemon, leader of the Aetolians, a man
+who could throw a good throw, and who was staunch also in close
+fight, while few could surpass him in debate when opinions were
+divided. He then with all sincerity and goodwill addressed them
+thus: "What, in heaven's name, do I now see? Is it not Hector
+come to life again? Every one made sure he had been killed by
+Ajax son of Telamon, but it seems that one of the gods has again
+rescued him. He has killed many of us Danaans already, and I take
+it will yet do so, for the hand of Jove must be with him or he
+would never dare show himself so masterful in the forefront of
+the battle. Now, therefore, let us all do as I say; let us order
+the main body of our forces to fall back upon the ships, but let
+those of us who profess to be the flower of the army stand firm,
+and see whether we cannot hold Hector back at the point of our
+spears as soon as he comes near us; I conceive that he will then
+think better of it before he tries to charge into the press of
+the Danaans."
+</para>
+
+<para>
+Thus did he speak, and they did even as he had said. Those who
+were about Ajax and King Idomeneus, the followers moreover of
+Teucer, Meriones, and Meges peer of Mars called all their best
+men about them and sustained the fight against Hector and the
+Trojans, but the main body fell back upon the ships of the
+Achaeans.
+</para>
+
+<para>
+The Trojans pressed forward in a dense body, with Hector striding
+on at their head. Before him went Phoebus Apollo shrouded in
+cloud about his shoulders. He bore aloft the terrible aegis with
+its shaggy fringe, which Vulcan the smith had given Jove to
+strike terror into the hearts of men. With this in his hand he
+led on the Trojans.
+</para>
+
+<para>
+The Argives held together and stood their ground. The cry of
+battle rose high from either side, and the arrows flew from the
+bowstrings. Many a spear sped from strong hands and fastened in
+the bodies of many a valiant warrior, while others fell to earth
+midway, before they could taste of man's fair flesh and glut
+themselves with blood. So long as Phoebus Apollo held his aegis
+quietly and without shaking it, the weapons on either side took
+effect and the people fell, but when he shook it straight in the
+face of the Danaans and raised his mighty battle-cry their hearts
+fainted within them and they forgot their former prowess. As when
+two wild beasts spring in the dead of night on a herd of cattle
+or a large flock of sheep when the herdsman is not there--even so
+were the Danaans struck helpless, for Apollo filled them with
+panic and gave victory to Hector and the Trojans.
+</para>
+
+<para>
+The fight then became more scattered and they killed one another
+where they best could. Hector killed Stichius and Arcesilaus, the
+one, leader of the Boeotians, and the other, friend and comrade
+of Menestheus. Aeneas killed Medon and Iasus. The first was
+bastard son to Oileus, and brother to Ajax, but he lived in
+Phylace away from his own country, for he had killed a man, a
+kinsman of his stepmother Eriopis whom Oileus had married. Iasus
+had become a leader of the Athenians, and was son of Sphelus the
+son of Boucolos. Polydamas killed Mecisteus, and Polites Echius,
+in the front of the battle, while Agenor slew Clonius. Paris
+struck Deiochus from behind in the lower part of the shoulder, as
+he was flying among the foremost, and the point of the spear went
+clean through him.
+</para>
+
+<para>
+While they were spoiling these heroes of their armour, the
+Achaeans were flying pell-mell to the trench and the set stakes,
+and were forced back within their wall. Hector then cried out to
+the Trojans, "Forward to the ships, and let the spoils be. If I
+see any man keeping back on the other side the wall away from the
+ships I will have him killed: his kinsmen and kinswomen shall not
+give him his dues of fire, but dogs shall tear him in pieces in
+front of our city."
+</para>
+
+<para>
+As he spoke he laid his whip about his horses' shoulders and
+called to the Trojans throughout their ranks; the Trojans shouted
+with a cry that rent the air, and kept their horses neck and neck
+with his own. Phoebus Apollo went before, and kicked down the
+banks of the deep trench into its middle so as to make a great
+broad bridge, as broad as the throw of a spear when a man is
+trying his strength. The Trojan battalions poured over the
+bridge, and Apollo with his redoubtable aegis led the way. He
+kicked down the wall of the Achaeans as easily as a child who
+playing on the sea-shore has built a house of sand and then kicks
+it down again and destroys it--even so did you, O Apollo, shed
+toil and trouble upon the Argives, filling them with panic and
+confusion.
+</para>
+
+<para>
+Thus then were the Achaeans hemmed in at their ships, calling out
+to one another and raising their hands with loud cries every man
+to heaven. Nestor of Gerene, tower of strength to the Achaeans,
+lifted up his hands to the starry firmament of heaven, and prayed
+more fervently than any of them. "Father Jove," said he, "if ever
+any one in wheat-growing Argos burned you fat thigh-bones of
+sheep or heifer and prayed that he might return safely home,
+whereon you bowed your head to him in assent, bear it in mind
+now, and suffer not the Trojans to triumph thus over the
+Achaeans."
+</para>
+
+<para>
+All-counselling Jove thundered loudly in answer to the prayer of
+the aged son of Neleus. When they heard Jove thunder they flung
+themselves yet more fiercely on the Achaeans. As a wave breaking
+over the bulwarks of a ship when the sea runs high before a
+gale--for it is the force of the wind that makes the waves so
+great--even so did the Trojans spring over the wall with a
+shout, and drive their chariots onwards. The two sides fought
+with their double-pointed spears in hand-to-hand encounter-the
+Trojans from their chariots, and the Achaeans climbing up into
+their ships and wielding the long pikes that were lying on the
+decks ready for use in a sea-fight, jointed and shod with bronze.
+</para>
+
+<para>
+Now Patroclus, so long as the Achaeans and Trojans were fighting
+about the wall, but were not yet within it and at the ships,
+remained sitting in the tent of good Eurypylus, entertaining him
+with his conversation and spreading herbs over his wound to ease
+his pain. When, however, he saw the Trojans swarming through the
+breach in the wall, while the Achaeans were clamouring and struck
+with panic, he cried aloud, and smote his two thighs with the
+flat of his hands. "Eurypylus," said he in his dismay, "I know
+you want me badly, but I cannot stay with you any longer, for
+there is hard fighting going on; a servant shall take care of you
+now, for I must make all speed to Achilles, and induce him to
+fight if I can; who knows but with heaven's help I may persuade
+him. A man does well to listen to the advice of a friend."
+</para>
+
+<para>
+When he had thus spoken he went his way. The Achaeans stood firm
+and resisted the attack of the Trojans, yet though these were
+fewer in number, they could not drive them back from the ships,
+neither could the Trojans break the Achaean ranks and make their
+way in among the tents and ships. As a carpenter's line gives a
+true edge to a piece of ship's timber, in the hand of some
+skilled workman whom Minerva has instructed in all kinds of
+useful arts--even so level was the issue of the fight between the
+two sides, as they fought some round one and some round another.
+</para>
+
+<para>
+Hector made straight for Ajax, and the two fought fiercely about
+the same ship. Hector could not force Ajax back and fire the
+ship, nor yet could Ajax drive Hector from the spot to which
+heaven had brought him.
+</para>
+
+<para>
+Then Ajax struck Caletor son of Clytius in the chest with a spear
+as he was bringing fire towards the ship. He fell heavily to the
+ground and the torch dropped from his hand. When Hector saw his
+cousin fallen in front of the ship he shouted to the Trojans and
+Lycians saying, "Trojans, Lycians, and Dardanians good in close
+fight, bate not a jot, but rescue the son of Clytius lest the
+Achaeans strip him of his armour now that he has fallen."
+</para>
+
+<para>
+He then aimed a spear at Ajax, and missed him, but he hit
+Lycophron a follower of Ajax, who came from Cythera, but was
+living with Ajax inasmuch as he had killed a man among the
+Cythereans. Hector's spear struck him on the head below the ear,
+and he fell headlong from the ship's prow on to the ground with
+no life left in him. Ajax shook with rage and said to his
+brother, "Teucer, my good fellow, our trusty comrade the son of
+Mastor has fallen, he came to live with us from Cythera and whom
+we honoured as much as our own parents. Hector has just killed
+him; fetch your deadly arrows at once and the bow which Phoebus
+Apollo gave you."
+</para>
+
+<para>
+Teucer heard him and hastened towards him with his bow and quiver
+in his hands. Forthwith he showered his arrows on the Trojans,
+and hit Cleitus the son of Pisenor, comrade of Polydamas the
+noble son of Panthous, with the reins in his hands as he was
+attending to his horses; he was in the middle of the very
+thickest part of the fight, doing good service to Hector and the
+Trojans, but evil had now come upon him, and not one of those who
+were fain to do so could avert it, for the arrow struck him on
+the back of the neck. He fell from his chariot and his horses
+shook the empty car as they swerved aside. King Polydamas saw
+what had happened, and was the first to come up to the horses; he
+gave them in charge to Astynous son of Protiaon, and ordered him
+to look on, and to keep the horses near at hand. He then went
+back and took his place in the front ranks.
+</para>
+
+<para>
+Teucer then aimed another arrow at Hector, and there would have
+been no more fighting at the ships if he had hit him and killed
+him then and there: Jove, however, who kept watch over Hector,
+had his eyes on Teucer, and deprived him of his triumph, by
+breaking his bowstring for him just as he was drawing it and
+about to take his aim; on this the arrow went astray and the bow
+fell from his hands. Teucer shook with anger and said to his
+brother, "Alas, see how heaven thwarts us in all we do; it has
+broken my bowstring and snatched the bow from my hand, though I
+strung it this selfsame morning that it might serve me for many
+an arrow."
+</para>
+
+<para>
+Ajax son of Telamon answered, "My good fellow, let your bow and
+your arrows be, for Jove has made them useless in order to spite
+the Danaans. Take your spear, lay your shield upon your shoulder,
+and both fight the Trojans yourself and urge others to do so.
+They may be successful for the moment but if we fight as we ought
+they will find it a hard matter to take the ships."
+</para>
+
+<para>
+Teucer then took his bow and put it by in his tent. He hung a
+shield four hides thick about his shoulders, and on his comely
+head he set his helmet well wrought with a crest of horse-hair
+that nodded menacingly above it; he grasped his redoubtable
+bronze-shod spear, and forthwith he was by the side of Ajax.
+</para>
+
+<para>
+When Hector saw that Teucer's bow was of no more use to him, he
+shouted out to the Trojans and Lycians, "Trojans, Lycians, and
+Dardanians good in close fight, be men, my friends, and show your
+mettle here at the ships, for I see the weapon of one of their
+chieftains made useless by the hand of Jove. It is easy to see
+when Jove is helping people and means to help them still further,
+or again when he is bringing them down and will do nothing for
+them; he is now on our side, and is going against the Argives.
+Therefore swarm round the ships and fight. If any of you is
+struck by spear or sword and loses his life, let him die; he dies
+with honour who dies fighting for his country; and he will leave
+his wife and children safe behind him, with his house and
+allotment unplundered if only the Achaeans can be driven back to
+their own land, they and their ships."
+</para>
+
+<para>
+With these words he put heart and soul into them all. Ajax on the
+other side exhorted his comrades saying, "Shame on you Argives,
+we are now utterly undone, unless we can save ourselves by
+driving the enemy from our ships. Do you think, if Hector takes
+them, that you will be able to get home by land? Can you not hear
+him cheering on his whole host to fire our fleet, and bidding
+them remember that they are not at a dance but in battle? Our
+only course is to fight them with might and main; we had better
+chance it, life or death, once for all, than fight long and
+without issue hemmed in at our ships by worse men than
+ourselves."
+</para>
+
+<para>
+With these words he put life and soul into them all. Hector then
+killed Schedius son of Perimedes, leader of the Phoceans, and
+Ajax killed Laodamas captain of foot soldiers and son to Antenor.
+Polydamas killed Otus of Cyllene a comrade of the son of Phyleus
+and chief of the proud Epeans. When Meges saw this he sprang upon
+him, but Polydamas crouched down, and he missed him, for Apollo
+would not suffer the son of Panthous to fall in battle; but the
+spear hit Croesmus in the middle of his chest, whereon he fell
+heavily to the ground, and Meges stripped him of his armour. At
+that moment the valiant soldier Dolops son of Lampus sprang upon
+Lampus was son of Laomedon and for his valour, while his son
+Dolops was versed in all the ways of war. He then struck the
+middle of the son of Phyleus' shield with his spear, setting on
+him at close quarters, but his good corslet made with plates of
+metal saved him; Phyleus had brought it from Ephyra and the river
+Selleis, where his host, King Euphetes, had given it him to wear
+in battle and protect him. It now served to save the life of his
+son. Then Meges struck the topmost crest of Dolops's bronze
+helmet with his spear and tore away its plume of horse-hair, so
+that all newly dyed with scarlet as it was it tumbled down into
+the dust. While he was still fighting and confident of victory,
+Menelaus came up to help Meges, and got by the side of Dolops
+unperceived; he then speared him in the shoulder, from behind,
+and the point, driven so furiously, went through into his chest,
+whereon he fell headlong. The two then made towards him to strip
+him of his armour, but Hector called on all his brothers for
+help, and he especially upbraided brave Melanippus son of
+Hiketaon, who erewhile used to pasture his herds of cattle in
+Percote before the war broke out; but when the ships of the
+Danaans came, he went back to Ilius, where he was eminent among
+the Trojans, and lived near Priam who treated him as one of his
+own sons. Hector now rebuked him and said, "Why, Melanippus, are
+we thus remiss? do you take no note of the death of your kinsman,
+and do you not see how they are trying to take Dolops's armour?
+Follow me; there must be no fighting the Argives from a distance
+now, but we must do so in close combat till either we kill them
+or they take the high wall of Ilius and slay her people."
+</para>
+
+<para>
+He led on as he spoke, and the hero Melanippus followed after.
+Meanwhile Ajax son of Telamon was cheering on the Argives. "My
+friends," he cried, "be men, and fear dishonour; quit yourselves
+in battle so as to win respect from one another. Men who respect
+each other's good opinion are less likely to be killed than those
+who do not, but in flight there is neither gain nor glory."
+</para>
+
+<para>
+Thus did he exhort men who were already bent upon driving back
+the Trojans. They laid his words to heart and hedged the ships as
+with a wall of bronze, while Jove urged on the Trojans. Menelaus
+of the loud battle-cry urged Antilochus on. "Antilochus," said
+he, "you are young and there is none of the Achaeans more fleet
+of foot or more valiant than you are. See if you cannot spring
+upon some Trojan and kill him."
+</para>
+
+<para>
+He hurried away when he had thus spurred Antilochus, who at once
+darted out from the front ranks and aimed a spear, after looking
+carefully round him. The Trojans fell back as he threw, and the
+dart did not speed from his hand without effect, for it struck
+Melanippus the proud son of Hiketaon in the breast by the nipple
+as he was coming forward, and his armour rang rattling round him
+as he fell heavily to the ground. Antilochus sprang upon him as a
+dog springs on a fawn which a hunter has hit as it was breaking
+away from its covert, and killed it. Even so, O Melanippus, did
+stalwart Antilochus spring upon you to strip you of your armour;
+but noble Hector marked him, and came running up to him through
+the thick of the battle. Antilochus, brave soldier though he was,
+would not stay to face him, but fled like some savage creature
+which knows it has done wrong, and flies, when it has killed a
+dog or a man who is herding his cattle, before a body of men can
+be gathered to attack it. Even so did the son of Nestor fly, and
+the Trojans and Hector with a cry that rent the air showered
+their weapons after him; nor did he turn round and stay his
+flight till he had reached his comrades.
+</para>
+
+<para>
+The Trojans, fierce as lions, were still rushing on towards the
+ships in fulfilment of the behests of Jove who kept spurring them
+on to new deeds of daring, while he deadened the courage of the
+Argives and defeated them by encouraging the Trojans. For he
+meant giving glory to Hector son of Priam, and letting him throw
+fire upon the ships, till he had fulfilled the unrighteous prayer
+that Thetis had made him; Jove, therefore, bided his time till he
+should see the glare of a blazing ship. From that hour he was
+about so to order that the Trojans should be driven back from the
+ships and to vouchsafe glory to the Achaeans. With this purpose
+he inspired Hector son of Priam, who was cager enough already, to
+assail the ships. His fury was as that of Mars, or as when a fire
+is raging in the glades of some dense forest upon the mountains;
+he foamed at the mouth, his eyes glared under his terrible
+eye-brows, and his helmet quivered on his temples by reason of
+the fury with which he fought. Jove from heaven was with him, and
+though he was but one against many, vouchsafed him victory and
+glory; for he was doomed to an early death, and already Pallas
+Minerva was hurrying on the hour of his destruction at the hands
+of the son of Peleus. Now, however, he kept trying to break the
+ranks of the enemy wherever he could see them thickest, and in
+the goodliest armour; but do what he might he could not break
+through them, for they stood as a tower foursquare, or as some
+high cliff rising from the grey sea that braves the anger of the
+gale, and of the waves that thunder up against it. He fell upon
+them like flames of fire from every quarter. As when a wave,
+raised mountain high by wind and storm, breaks over a ship and
+covers it deep in foam, the fierce winds roar against the mast,
+the hearts of the sailors fail them for fear, and they are saved
+but by a very little from destruction--even so were the hearts of
+the Achaeans fainting within them. Or as a savage lion attacking
+a herd of cows while they are feeding by thousands in the
+low-lying meadows by some wide-watered shore--the herdsman is at
+his wit's end how to protect his herd and keeps going about now
+in the van and now in the rear of his cattle, while the lion
+springs into the thick of them and fastens on a cow so that they
+all tremble for fear--even so were the Achaeans utterly
+panic-stricken by Hector and father Jove. Nevertheless Hector
+only killed Periphetes of Mycenae; he was son of Copreus who was
+wont to take the orders of King Eurystheus to mighty Hercules,
+but the son was a far better man than the father in every way; he
+was fleet of foot, a valiant warrior, and in understanding ranked
+among the foremost men of Mycenae. He it was who then afforded
+Hector a triumph, for as he was turning back he stumbled against
+the rim of his shield which reached his feet, and served to keep
+the javelins off him. He tripped against this and fell face
+upward, his helmet ringing loudly about his head as he did so.
+Hector saw him fall and ran up to him; he then thrust a spear
+into his chest, and killed him close to his own comrades. These,
+for all their sorrow, could not help him for they were themselves
+terribly afraid of Hector.
+</para>
+
+<para>
+They had now reached the ships and the prows of those that had
+been drawn up first were on every side of them, but the Trojans
+came pouring after them. The Argives were driven back from the
+first row of ships, but they made a stand by their tents without
+being broken up and scattered; shame and fear restrained them.
+They kept shouting incessantly to one another, and Nestor of
+Gerene, tower of strength to the Achaeans, was loudest in
+imploring every man by his parents, and beseeching him to stand
+firm.
+</para>
+
+<para>
+"Be men, my friends," he cried, "and respect one another's good
+opinion. Think, all of you, on your children, your wives, your
+property, and your parents whether these be alive or dead. On
+their behalf though they are not here, I implore you to stand
+firm, and not to turn in flight."
+</para>
+
+<para>
+With these words he put heart and soul into them all. Minerva
+lifted the thick veil of darkness from their eyes, and much light
+fell upon them, alike on the side of the ships and on that where
+the fight was raging. They could see Hector and all his men, both
+those in the rear who were taking no part in the battle, and
+those who were fighting by the ships.
+</para>
+
+<para>
+Ajax could not bring himself to retreat along with the rest, but
+strode from deck to deck with a great sea-pike in his hands
+twelve cubits long and jointed with rings. As a man skilled in
+feats of horsemanship couples four horses together and comes
+tearing full speed along the public way from the country into
+some large town--many both men and women marvel as they see him
+for he keeps all the time changing his horse, springing from one
+to another without ever missing his feet while the horses are at
+a gallop--even so did Ajax go striding from one ship's deck to
+another, and his voice went up into the heavens. He kept on
+shouting his orders to the Danaans and exhorting them to defend
+their ships and tents; neither did Hector remain within the main
+body of the Trojan warriors, but as a dun eagle swoops down upon
+a flock of wild-fowl feeding near a river-geese, it may be, or
+cranes, or long-necked swans--even so did Hector make straight
+for a dark-prowed ship, rushing right towards it; for Jove with
+his mighty hand impelled him forward, and roused his people to
+follow him.
+</para>
+
+<para>
+And now the battle again raged furiously at the ships. You would
+have thought the men were coming on fresh and unwearied, so
+fiercely did they fight; and this was the mind in which they
+were--the Achaeans did not believe they should escape destruction
+but thought themselves doomed, while there was not a Trojan but
+his heart beat high with the hope of firing the ships and putting
+the Achaean heroes to the sword.
+</para>
+
+<para>
+Thus were the two sides minded. Then Hector seized the stern of
+the good ship that had brought Protesilaus to Troy, but never
+bore him back to his native land. Round this ship there raged a
+close hand-to-hand fight between Danaans and Trojans. They did
+not fight at a distance with bows and javelins, but with one mind
+hacked at one another in close combat with their mighty swords
+and spears pointed at both ends; they fought moreover with keen
+battle-axes and with hatchets. Many a good stout blade hilted and
+scabbarded with iron, fell from hand or shoulder as they fought,
+and the earth ran red with blood. Hector, when he had seized the
+ship, would not loose his hold but held on to its curved stern
+and shouted to the Trojans, "Bring fire, and raise the battle-cry
+all of you with a single voice. Now has Jove vouchsafed us a day
+that will pay us for all the rest; this day we shall take the
+ships which came hither against heaven's will, and which have
+caused us such infinite suffering through the cowardice of our
+councillors, who when I would have done battle at the ships held
+me back and forbade the host to follow me; if Jove did then
+indeed warp our judgements, himself now commands me and cheers me
+on."
+</para>
+
+<para>
+As he spoke thus the Trojans sprang yet more fiercely on the
+Achaeans, and Ajax no longer held his ground, for he was overcome
+by the darts that were flung at him, and made sure that he was
+doomed. Therefore he left the raised deck at the stern, and
+stepped back on to the seven-foot bench of the oarsmen. Here he
+stood on the look-out, and with his spear held back Trojan whom
+he saw bringing fire to the ships. All the time he kept on
+shouting at the top of his voice and exhorting the Danaans. "My
+friends," he cried, "Danaan heroes, servants of Mars, be men my
+friends, and fight with might and with main. Can we hope to find
+helpers hereafter, or a wall to shield us more surely than the
+one we have? There is no strong city within reach, whence we may
+draw fresh forces to turn the scales in our favour. We are on the
+plain of the armed Trojans with the sea behind us, and far from
+our own country. Our salvation, therefore, is in the might of our
+hands and in hard fighting."
+</para>
+
+<para>
+As he spoke he wielded his spear with still greater fury, and
+when any Trojan made towards the ships with fire at Hector's
+bidding, he would be on the look-out for him, and drive at him
+with his long spear. Twelve men did he thus kill in hand-to-hand
+fight before the ships.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK XVI</title>
+
+<para>
+THUS did they fight about the ship of Protesilaus. Then Patroclus
+drew near to Achilles with tears welling from his eyes, as from
+some spring whose crystal stream falls over the ledges of a high
+precipice. When Achilles saw him thus weeping he was sorry for
+him and said, "Why, Patroclus, do you stand there weeping like
+some silly child that comes running to her mother, and begs to be
+taken up and carried--she catches hold of her mother's dress to
+stay her though she is in a hurry, and looks tearfully up until
+her mother carries her--even such tears, Patroclus, are you now
+shedding. Have you anything to say to the Myrmidons or to myself?
+or have you had news from Phthia which you alone know? They tell
+me Menoetius son of Actor is still alive, as also Peleus son of
+Aeacus, among the Myrmidons--men whose loss we two should
+bitterly deplore; or are you grieving about the Argives and the
+way in which they are being killed at the ships, through their
+own high-handed doings? Do not hide anything from me but tell me
+that both of us may know about it."
+</para>
+
+<para>
+Then, O knight Patroclus, with a deep sigh you answered,
+"Achilles, son of Peleus, foremost champion of the Achaeans, do
+not be angry, but I weep for the disaster that has now befallen
+the Argives. All those who have been their champions so far are
+lying at the ships, wounded by sword or spear. Brave Diomed son
+of Tydeus has been hit with a spear, while famed Ulysses and
+Agamemnon have received sword-wounds; Eurypylus again has been
+struck with an arrow in the thigh; skilled apothecaries are
+attending to these heroes, and healing them of their wounds; are
+you still, O Achilles, so inexorable? May it never be my lot to
+nurse such a passion as you have done, to the baning of your own
+good name. Who in future story will speak well of you unless you
+now save the Argives from ruin? You know no pity; knight Peleus
+was not your father nor Thetis your mother, but the grey sea bore
+you and the sheer cliffs begot you, so cruel and remorseless are
+you. If however you are kept back through knowledge of some
+oracle, or if your mother Thetis has told you something from the
+mouth of Jove, at least send me and the Myrmidons with me, if I
+may bring deliverance to the Danaans. Let me moreover wear your
+armour; the Trojans may thus mistake me for you and quit the
+field, so that the hard-pressed sons of the Achaeans may have
+breathing time--which while they are fighting may hardly be. We
+who are fresh might soon drive tired men back from our ships and
+tents to their own city."
+</para>
+
+<para>
+He knew not what he was asking, nor that he was suing for his own
+destruction. Achilles was deeply moved and answered, "What, noble
+Patroclus, are you saying? I know no prophesyings which I am
+heeding, nor has my mother told me anything from the mouth of
+Jove, but I am cut to the very heart that one of my own rank
+should dare to rob me because he is more powerful than I am.
+This, after all that I have gone through, is more than I can
+endure. The girl whom the sons of the Achaeans chose for me, whom
+I won as the fruit of my spear on having sacked a city--her has
+King Agamemnon taken from me as though I were some common
+vagrant. Still, let bygones be bygones: no man may keep his anger
+for ever; I said I would not relent till battle and the cry of
+war had reached my own ships; nevertheless, now gird my armour
+about your shoulders, and lead the Myrmidons to battle, for the
+dark cloud of Trojans has burst furiously over our fleet; the
+Argives are driven back on to the beach, cooped within a narrow
+space, and the whole people of Troy has taken heart to sally out
+against them, because they see not the visor of my helmet
+gleaming near them. Had they seen this, there would not have been
+a creek nor grip that had not been filled with their dead as they
+fled back again. And so it would have been, if only King
+Agamemnon had dealt fairly by me. As it is the Trojans have beset
+our host. Diomed son of Tydeus no longer wields his spear to
+defend the Danaans, neither have I heard the voice of the son of
+Atreus coming from his hated head, whereas that of murderous
+Hector rings in my cars as he gives orders to the Trojans, who
+triumph over the Achaeans and fill the whole plain with their cry
+of battle. But even so, Patroclus, fall upon them and save the
+fleet, lest the Trojans fire it and prevent us from being able to
+return. Do, however, as I now bid you, that you may win me great
+honour from all the Danaans, and that they may restore the girl
+to me again and give me rich gifts into the bargain. When you
+have driven the Trojans from the ships, come back again. Though
+Juno's thundering husband should put triumph within your reach,
+do not fight the Trojans further in my absence, or you will rob
+me of glory that should be mine. And do not for lust of battle go
+on killing the Trojans nor lead the Achaeans on to Ilius, lest
+one of the ever-living gods from Olympus attack you--for Phoebus
+Apollo loves them well: return when you have freed the ships from
+peril, and let others wage war upon the plain. Would, by father
+Jove, Minerva, and Apollo, that not a single man of all the
+Trojans might be left alive, nor yet of the Argives, but that we
+two might be alone left to tear aside the mantle that veils the
+brow of Troy."
+</para>
+
+<para>
+Thus did they converse. But Ajax could no longer hold his ground
+for the shower of darts that rained upon him; the will of Jove
+and the javelins of the Trojans were too much for him; the helmet
+that gleamed about his temples rang with the continuous clatter
+of the missiles that kept pouring on to it and on to the
+cheek-pieces that protected his face. Moreover his left shoulder
+was tired with having held his shield so long, yet for all this,
+let fly at him as they would, they could not make him give
+ground. He could hardly draw his breath, the sweat rained from
+every pore of his body, he had not a moment's respite, and on all
+sides he was beset by danger upon danger.
+</para>
+
+<para>
+And now, tell me, O Muses that hold your mansions on Olympus, how
+fire was thrown upon the ships of the Achaeans. Hector came close
+up and let drive with his great sword at the ashen spear of Ajax.
+He cut it clean in two just behind where the point was fastened
+on to the shaft of the spear. Ajax, therefore, had now nothing
+but a headless spear, while the bronze point flew some way off
+and came ringing down on to the ground. Ajax knew the hand of
+heaven in this, and was dismayed at seeing that Jove had now left
+him utterly defenceless and was willing victory for the Trojans.
+Therefore he drew back, and the Trojans flung fire upon the ship
+which was at once wrapped in flame.
+</para>
+
+<para>
+The fire was now flaring about the ship's stern, whereon Achilles
+smote his two thighs and said to Patroclus, "Up, noble knight,
+for I see the glare of hostile fire at our fleet; up, lest they
+destroy our ships, and there be no way by which we may retreat.
+Gird on your armour at once while I call our people together."
+</para>
+
+<para>
+As he spoke Patroclus put on his armour. First he greaved his
+legs with greaves of good make, and fitted with ancle-clasps of
+silver; after this he donned the cuirass of the son of Aeacus,
+richly inlaid and studded. He hung his silver-studded sword of
+bronze about his shoulders, and then his mighty shield. On his
+comely head he set his helmet, well wrought, with a crest of
+horse-hair that nodded menacingly above it. He grasped two
+redoubtable spears that suited his hands, but he did not take the
+spear of noble Achilles, so stout and strong, for none other of
+the Achaeans could wield it, though Achilles could do so easily.
+This was the ashen spear from Mount Pelion, which Chiron had cut
+upon a mountain top and had given to Peleus, wherewith to deal
+out death among heroes. He bade Automedon yoke his horses with
+all speed, for he was the man whom he held in honour next after
+Achilles, and on whose support in battle he could rely most
+firmly. Automedon therefore yoked the fleet horses Xanthus and
+Balius, steeds that could fly like the wind: these were they whom
+the harpy Podarge bore to the west wind, as she was grazing in a
+meadow by the waters of the river Oceanus. In the side traces he
+set the noble horse Pedasus, whom Achilles had brought away with
+him when he sacked the city of Eetion, and who, mortal steed
+though he was, could take his place along with those that were
+immortal.
+</para>
+
+<para>
+Meanwhile Achilles went about everywhere among the tents, and
+bade his Myrmidons put on their armour. Even as fierce ravening
+wolves that are feasting upon a homed stag which they have killed
+upon the mountains, and their jaws are red with blood--they go in
+a pack to lap water from the clear spring with their long thin
+tongues; and they reek of blood and slaughter; they know not what
+fear is, for it is hunger drives them--even so did the leaders
+and counsellors of the Myrmidons gather round the good squire of
+the fleet descendant of Aeacus, and among them stood Achilles
+himself cheering on both men and horses.
+</para>
+
+<para>
+Fifty ships had noble Achilles brought to Troy, and in each there
+was a crew of fifty oarsmen. Over these he set five captains whom
+he could trust, while he was himself commander over them all.
+Menesthius of the gleaming corslet, son to the river Spercheius
+that streams from heaven, was captain of the first company. Fair
+Polydora daughter of Peleus bore him to ever-flowing
+Spercheius--a woman mated with a god--but he was called son of
+Borus son of Perieres, with whom his mother was living as his
+wedded wife, and who gave great wealth to gain her. The second
+company was led by noble Eudorus, son to an unwedded woman.
+Polymele, daughter of Phylas the graceful dancer, bore him; the
+mighty slayer of Argos was enamoured of her as he saw her among
+the singing women at a dance held in honour of Diana the rushing
+huntress of the golden arrows; he therefore--Mercury, giver of
+all good--went with her into an upper chamber, and lay with her
+in secret, whereon she bore him a noble son Eudorus, singularly
+fleet of foot and in fight valiant. When Ilithuia goddess of the
+pains of child-birth brought him to the light of day, and he saw
+the face of the sun, mighty Echecles son of Actor took the mother
+to wife, and gave great wealth to gain her, but her father Phylas
+brought the child up, and took care of him, doting as fondly upon
+him as though he were his own son. The third company was led by
+Pisander son of Maemalus, the finest spearman among all the
+Myrmidons next to Achilles' own comrade Patroclus. The old knight
+Phoenix was captain of the fourth company, and Alcimedon, noble
+son of Laerceus of the fifth.
+</para>
+
+<para>
+When Achilles had chosen his men and had stationed them all with
+their captains, he charged them straitly saying, "Myrmidons,
+remember your threats against the Trojans while you were at the
+ships in the time of my anger, and you were all complaining of
+me. 'Cruel son of Peleus,' you would say, 'your mother must have
+suckled you on gall, so ruthless are you. You keep us here at the
+ships against our will; if you are so relentless it were better
+we went home over the sea.' Often have you gathered and thus
+chided with me. The hour is now come for those high feats of arms
+that you have so long been pining for, therefore keep high hearts
+each one of you to do battle with the Trojans."
+</para>
+
+<para>
+With these words he put heart and soul into them all, and they
+serried their companies yet more closely when they heard the of
+their king. As the stones which a builder sets in the wall of
+some high house which is to give shelter from the winds--even so
+closely were the helmets and bossed shields set against one
+another. Shield pressed on shield, helm on helm, and man on man;
+so close were they that the horse-hair plumes on the gleaming
+ridges of their helmets touched each other as they bent their
+heads.
+</para>
+
+<para>
+In front of them all two men put on their armour--Patroclus and
+Automedon--two men, with but one mind to lead the Myrmidons. Then
+Achilles went inside his tent and opened the lid of the strong
+chest which silver-footed Thetis had given him to take on board
+ship, and which she had filled with shirts, cloaks to keep out
+the cold, and good thick rugs. In this chest he had a cup of rare
+workmanship, from which no man but himself might drink, nor would
+he make offering from it to any other god save only to father
+Jove. He took the cup from the chest and cleansed it with
+sulphur; this done he rinsed it clean water, and after he had
+washed his hands he drew wine. Then he stood in the middle of the
+court and prayed, looking towards heaven, and making his
+drink-offering of wine; nor was he unseen of Jove whose joy is in
+thunder. "King Jove," he cried, "lord of Dodona, god of the
+Pelasgi, who dwellest afar, you who hold wintry Dodona in your
+sway, where your prophets the Selli dwell around you with their
+feet unwashed and their couches made upon the ground--if you
+heard me when I prayed to you aforetime, and did me honour while
+you sent disaster on the Achaeans, vouchsafe me now the
+fulfilment of yet this further prayer. I shall stay here where my
+ships are lying, but I shall send my comrade into battle at the
+head of many Myrmidons. Grant, O all-seeing Jove, that victory
+may go with him; put your courage into his heart that Hector may
+learn whether my squire is man enough to fight alone, or whether
+his might is only then so indomitable when I myself enter the
+turmoil of war. Afterwards when he has chased the fight and the
+cry of battle from the ships, grant that he may return unharmed,
+with his armour and his comrades, fighters in close combat."
+</para>
+
+<para>
+Thus did he pray, and all-counselling Jove heard his prayer.
+Part of it he did indeed vouchsafe him--but not the whole. He
+granted that Patroclus should thrust back war and battle from the
+ships, but refused to let him come safely out of the fight.
+</para>
+
+<para>
+When he had made his drink-offering and had thus prayed, Achilles
+went inside his tent and put back the cup into his chest.
+</para>
+
+<para>
+Then he again came out, for he still loved to look upon the
+fierce fight that raged between the Trojans and Achaeans.
+</para>
+
+<para>
+Meanwhile the armed band that was about Patroclus marched on till
+they sprang high in hope upon the Trojans. They came swarming out
+like wasps whose nests are by the roadside, and whom silly
+children love to tease, whereon any one who happens to be passing
+may get stung--or again, if a wayfarer going along the road vexes
+them by accident, every wasp will come flying out in a fury to
+defend his little ones--even with such rage and courage did the
+Myrmidons swarm from their ships, and their cry of battle rose
+heavenwards. Patroclus called out to his men at the top of his
+voice, "Myrmidons, followers of Achilles son of Peleus, be men my
+friends, fight with might and with main, that we may win glory
+for the son of Peleus, who is far the foremost man at the ships
+of the Argives--he, and his close fighting followers. The son of
+Atreus King Agamemnon will thus learn his folly in showing no
+respect to the bravest of the Achaeans."
+</para>
+
+<para>
+With these words he put heart and soul into them all, and they
+fell in a body upon the Trojans. The ships rang again with the
+cry which the Achaeans raised, and when the Trojans saw the brave
+son of Menoetius and his squire all gleaming in their armour,
+they were daunted and their battalions were thrown into
+confusion, for they thought the fleet son of Peleus must now have
+put aside his anger, and have been reconciled to Agamemnon; every
+one, therefore, looked round about to see whither he might fly
+for safety.
+</para>
+
+<para>
+Patroclus first aimed a spear into the middle of the press where
+men were packed most closely, by the stern of the ship of
+Protesilaus. He hit Pyraechmes who had led his Paeonian horsemen
+from the Amydon and the broad waters of the river Axius; the
+spear struck him on the right shoulder, and with a groan he fell
+backwards in the dust; on this his men were thrown into
+confusion, for by killing their leader, who was the finest
+soldier among them, Patroclus struck panic into them all. He thus
+drove them from the ship and quenched the fire that was then
+blazing--leaving the half-burnt ship to lie where it was. The
+Trojans were now driven back with a shout that rent the skies,
+while the Danaans poured after them from their ships, shouting
+also without ceasing. As when Jove, gatherer of the
+thunder-cloud, spreads a dense canopy on the top of some lofty
+mountain, and all the peaks, the jutting headlands, and forest
+glades show out in the great light that flashes from the bursting
+heavens, even so when the Danaans had now driven back the fire
+from their ships, they took breath for a little while; but the
+fury of the fight was not yet over, for the Trojans were not
+driven back in utter rout, but still gave battle, and were ousted
+from their ground only by sheer fighting.
+</para>
+
+<para>
+The fight then became more scattered, and the chieftains killed
+one another when and how they could. The valiant son of Menoetius
+first drove his spear into the thigh of Areilycus just as he was
+turning round; the point went clean through, and broke the bone
+so that he fell forward. Meanwhile Menelaus struck Thoas in the
+chest, where it was exposed near the rim of his shield, and he
+fell dead. The son of Phyleus saw Amphiclus about to attack him,
+and ere he could do so took aim at the upper part of his thigh,
+where the muscles are thicker than in any other part; the spear
+tore through all the sinews of the leg, and his eyes were closed
+in darkness. Of the sons of Nestor one, Antilochus, speared
+Atymnius, driving the point of the spear through his throat, and
+down he fell. Maris then sprang on Antilochus in hand-to-hand
+fight to avenge his brother, and bestrode the body spear in hand;
+but valiant Thrasymedes was too quick for him, and in a moment
+had struck him in the shoulder ere he could deal his blow; his
+aim was true, and the spear severed all the muscles at the root
+of his arm, and tore them right down to the bone, so he fell
+heavily to the ground and his eyes were closed in darkness. Thus
+did these two noble comrades of Sarpedon go down to Erebus slain
+by the two sons of Nestor; they were the warrior sons of
+Amisodorus, who had reared the invincible Chimaera, to the bane
+of many. Ajax son of Oileus sprang on Cleobulus and took him
+alive as he was entangled in the crush; but he killed him then
+and there by a sword-blow on the neck. The sword reeked with his
+blood, while dark death and the strong hand of fate gripped him
+and closed his eyes.
+</para>
+
+<para>
+Peneleos and Lycon now met in close fight, for they had missed
+each other with their spears. They had both thrown without
+effect, so now they drew their swords. Lycon struck the plumed
+crest of Peneleos' helmet but his sword broke at the hilt, while
+Peneleos smote Lycon on the neck under the ear. The blade sank so
+deep that the head was held on by nothing but the skin, and there
+was no more life left in him. Meriones gave chase to Acamas on
+foot and caught him up just as he was about to mount his chariot;
+he drove a spear through his right shoulder so that he fell
+headlong from the car, and his eyes were closed in darkness.
+Idomeneus speared Erymas in the mouth; the bronze point of the
+spear went clean through it beneath the brain, crashing in among
+the white bones and smashing them up. His teeth were all of them
+knocked out and the blood came gushing in a stream from both his
+eyes; it also came gurgling up from his mouth and nostrils, and
+the darkness of death enfolded him round about.
+</para>
+
+<para>
+Thus did these chieftains of the Danaans each of them kill his
+man. As ravening wolves seize on kids or lambs, fastening on them
+when they are alone on the hillsides and have strayed from the
+main flock through the carelessness of the shepherd--and when the
+wolves see this they pounce upon them at once because they cannot
+defend themselves--even so did the Danaans now fall on the
+Trojans, who fled with ill-omened cries in their panic and had no
+more fight left in them.
+</para>
+
+<para>
+Meanwhile great Ajax kept on trying to drive a spear into Hector,
+but Hector was so skilful that he held his broad shoulders well
+under cover of his ox-hide shield, ever on the look-out for the
+whizzing of the arrows and the heavy thud of the spears. He well
+knew that the fortunes of the day had changed, but still stood
+his ground and tried to protect his comrades.
+</para>
+
+<para>
+As when a cloud goes up into heaven from Olympus, rising out of a
+clear sky when Jove is brewing a gale--even with such panic
+stricken rout did the Trojans now fly, and there was no order in
+their going. Hector's fleet horses bore him and his armour out of
+the fight, and he left the Trojan host penned in by the deep
+trench against their will. Many a yoke of horses snapped the pole
+of their chariots in the trench and left their master's car
+behind them. Patroclus gave chase, calling impetuously on the
+Danaans and full of fury against the Trojans, who, being now no
+longer in a body, filled all the ways with their cries of panic
+and rout; the air was darkened with the clouds of dust they
+raised, and the horses strained every nerve in their flight from
+the tents and ships towards the city.
+</para>
+
+<para>
+Patroclus kept on heading his horses wherever he saw most men
+flying in confusion, cheering on his men the while. Chariots were
+being smashed in all directions, and many a man came tumbling
+down from his own car to fall beneath the wheels of that of
+Patroclus, whose immortal steeds, given by the gods to Peleus,
+sprang over the trench at a bound as they sped onward. He was
+intent on trying to get near Hector, for he had set his heart on
+spearing him, but Hector's horses were now hurrying him away. As
+the whole dark earth bows before some tempest on an autumn day
+when Jove rains his hardest to punish men for giving crooked
+judgement in their courts, and arriving justice therefrom without
+heed to the decrees of heaven--all the rivers run full and the
+torrents tear many a new channel as they roar headlong from the
+mountains to the dark sea, and it fares ill with the works of
+men--even such was the stress and strain of the Trojan horses in
+their flight.
+</para>
+
+<para>
+Patroclus now cut off the battalions that were nearest to him and
+drove them back to the ships. They were doing their best to reach
+the city, but he would not let them, and bore down on them
+between the river and the ships and wall. Many a fallen comrade
+did he then avenge. First he hit Pronous with a spear on the
+chest where it was exposed near the rim of his shield, and he
+fell heavily to the ground. Next he sprang on Thestor son of
+Enops, who was sitting all huddled up in his chariot, for he had
+lost his head and the reins had been torn out of his hands.
+Patroclus went up to him and drove a spear into his right jaw; he
+thus hooked him by the teeth and the spear pulled him over the
+rim of his car, as one who sits at the end of some jutting rock
+and draws a strong fish out of the sea with a hook and a line--
+even so with his spear did he pull Thestor all gaping from his
+chariot; he then threw him down on his face and he died while
+falling. On this, as Erylaus was on to attack him, he struck him
+full on the head with a stone, and his brains were all battered
+inside his helmet, whereon he fell headlong to the ground and the
+pangs of death took hold upon him. Then he laid low, one after
+the other, Erymas, Amphoterus, Epaltes, Tlepolemus, Echius son of
+Damastor, Pyris, lpheus, Euippus and Polymelus son of Argeas.
+</para>
+
+<para>
+Now when Sarpedon saw his comrades, men who wore ungirdled
+tunics, being overcome by Patroclus son of Menoetius, he rebuked
+the Lycians saying. "Shame on you, where are you flying to? Show
+your mettle; I will myself meet this man in fight and learn who
+it is that is so masterful; he has done us much hurt, and has
+stretched many a brave man upon the ground."
+</para>
+
+<para>
+He sprang from his chariot as he spoke, and Patroclus, when he
+saw this, leaped on to the ground also. The two then rushed at
+one another with loud cries like eagle-beaked crook-taloned
+vultures that scream and tear at one another in some high
+mountain fastness.
+</para>
+
+<para>
+The son of scheming Saturn looked down upon them in pity and said
+to Juno who was his wife and sister, "Alas, that it should be the
+lot of Sarpedon whom I love so dearly to perish by the hand of
+Patroclus. I am in two minds whether to catch him up out of the
+fight and set him down safe and sound in the fertile land of
+Lycia, or to let him now fall by the hand of the son of
+Menoetius."
+</para>
+
+<para>
+And Juno answered, "Most dread son of Saturn, what is this that
+you are saying? Would you snatch a mortal man, whose doom has
+long been fated, out of the jaws of death? Do as you will, but we
+shall not all of us be of your mind. I say further, and lay my
+saying to your heart, that if you send Sarpedon safely to his own
+home, some other of the gods will be also wanting to escort his
+son out of battle, for there are many sons of gods fighting round
+the city of Troy, and you will make every one jealous. If,
+however, you are fond of him and pity him, let him indeed fall by
+the hand of Patroclus, but as soon as the life is gone out of
+him, send Death and sweet Sleep to bear him off the field and
+take him to the broad lands of Lycia, where his brothers and his
+kinsmen will bury him with mound and pillar, in due honour to the
+dead."
+</para>
+
+<para>
+The sire of gods and men assented, but he shed a rain of blood
+upon the earth in honour of his son whom Patroclus was about to
+kill on the rich plain of Troy far from his home.
+</para>
+
+<para>
+When they were now come close to one another Patroclus struck
+Thrasydemus, the brave squire of Sarpedon, in the lower part of
+the belly, and killed him. Sarpedon then aimed a spear at
+Patroclus and missed him, but he struck the horse Pedasus in the
+right shoulder, and it screamed aloud as it lay, groaning in the
+dust until the life went out of it. The other two horses began to
+plunge; the pole of the chariot cracked and they got entangled in
+the reins through the fall of the horse that was yoked along with
+them; but Automedon knew what to do; without the loss of a moment
+he drew the keen blade that hung by his sturdy thigh and cut the
+third horse adrift; whereon the other two righted themselves, and
+pulling hard at the reins again went together into battle.
+</para>
+
+<para>
+Sarpedon now took a second aim at Patroclus, and again missed
+him, the point of the spear passed over his left shoulder without
+hitting him. Patroclus then aimed in his turn, and the spear sped
+not from his hand in vain, for he hit Sarpedon just where the
+midriff surrounds the ever-beating heart. He fell like some oak
+or silver poplar or tall pine to which woodmen have laid their
+axes upon the mountains to make timber for ship-building--even so
+did he lie stretched at full length in front of his chariot and
+horses, moaning and clutching at the blood-stained dust. As when
+a lion springs with a bound upon a herd of cattle and fastens on
+a great black bull which dies bellowing in its clutches--even so
+did the leader of the Lycian warriors struggle in death as he
+fell by the hand of Patroclus. He called on his trusty comrade
+and said, "Glaucus, my brother, hero among heroes, put forth all
+your strength, fight with might and main, now if ever quit
+yourself like a valiant soldier. First go about among the Lycian
+captains and bid them fight for Sarpedon; then yourself also do
+battle to save my armour from being taken. My name will haunt you
+henceforth and for ever if the Achaeans rob me of my armour now
+that I have fallen at their ships. Do your very utmost and call
+all my people together."
+</para>
+
+<para>
+Death closed his eyes as he spoke. Patroclus planted his heel on
+his breast and drew the spear from his body, whereon his senses
+came out along with it, and he drew out both spear-point and
+Sarpedon's soul at the same time. Hard by the Myrmidons held his
+snorting steeds, who were wild with panic at finding themselves
+deserted by their lords.
+</para>
+
+<para>
+Glaucus was overcome with grief when he heard what Sarpedon said,
+for he could not help him. He had to support his arm with his
+other hand, being in great pain through the wound which Teucer's
+arrow had given him when Teucer was defending the wall as he,
+Glaucus, was assailing it. Therefore he prayed to far-darting
+Apollo saying, "Hear me O king from your seat, may be in the rich
+land of Lycia, or may be in Troy, for in all places you can hear
+the prayer of one who is in distress, as I now am. I have a
+grievous wound; my hand is aching with pain, there is no
+staunching the blood, and my whole arm drags by reason of my
+hurt, so that I cannot grasp my sword nor go among my foes and
+fight them, thou our prince, Jove's son Sarpedon, is slain. Jove
+defended not his son, do you, therefore, O king, heal me of my
+wound, ease my pain and grant me strength both to cheer on the
+Lycians and to fight along with them round the body of him who
+has fallen."
+</para>
+
+<para>
+Thus did he pray, and Apollo heard his prayer. He eased his pain,
+staunched the black blood from the wound, and gave him new
+strength. Glaucus perceived this, and was thankful that the
+mighty god had answered his prayer; forthwith, therefore, he went
+among the Lycian captains, and bade them come to fight about the
+body of Sarpedon. From these he strode on among the Trojans to
+Polydamas son of Panthous and Agenor; he then went in search of
+Aeneas and Hector, and when he had found them he said, "Hector,
+you have utterly forgotten your allies, who languish here for
+your sake far from friends and home while you do nothing to
+support them. Sarpedon leader of the Lycian warriors has fallen--
+he who was at once the right and might of Lycia; Mars has laid
+him low by the spear of Patroclus. Stand by him, my friends, and
+suffer not the Myrmidons to strip him of his armour, nor to treat
+his body with contumely in revenge for all the Danaans whom we
+have speared at the ships."
+</para>
+
+<para>
+As he spoke the Trojans were plunged in extreme and ungovernable
+grief; for Sarpedon, alien though he was, had been one of the
+main stays of their city, both as having much people with him,
+and himself the foremost among them all. Led by Hector, who was
+infuriated by the fall of Sarpedon, they made instantly for the
+Danaans with all their might, while the undaunted spirit of
+Patroclus son of Menoetius cheered on the Achaeans. First he
+spoke to the two Ajaxes, men who needed no bidding. "Ajaxes,"
+said he, "may it now please you to show yourselves the men you
+have always been, or even better--Sarpedon is fallen--he who was
+first to overleap the wall of the Achaeans; let us take the body
+and outrage it; let us strip the armour from his shoulders, and
+kill his comrades if they try to rescue his body."
+</para>
+
+<para>
+He spoke to men who of themselves were full eager; both sides,
+therefore, the Trojans and Lycians on the one hand, and the
+Myrmidons and Achaeans on the other, strengthened their
+battalions, and fought desperately about the body of Sarpedon,
+shouting fiercely the while. Mighty was the din of their armour
+as they came together, and Jove shed a thick darkness over the
+fight, to increase the toil of the battle over the body of his
+son.
+</para>
+
+<para>
+At first the Trojans made some headway against the Achaeans, for
+one of the best men among the Myrmidons was killed, Epeigeus, son
+of noble Agacles who had erewhile been king in the good city of
+Budeum; but presently, having killed a valiant kinsman of his
+own, he took refuge with Peleus and Thetis, who sent him to Ilius
+the land of noble steeds to fight the Trojans under Achilles.
+Hector now struck him on the head with a stone just as he had
+caught hold of the body, and his brains inside his helmet were
+all battered in, so that he fell face foremost upon the body of
+Sarpedon, and there died. Patroclus was enraged by the death of
+his comrade, and sped through the front ranks as swiftly as a
+hawk that swoops down on a flock of daws or starlings. Even so
+swiftly, O noble knight Patroclus, did you make straight for the
+Lycians and Trojans to avenge your comrade. Forthwith he struck
+Sthenelaus the son of Ithaemenes on the neck with a stone, and
+broke the tendons that join it to the head and spine. On this
+Hector and the front rank of his men gave ground. As far as a man
+can throw a javelin when competing for some prize, or even in
+battle--so far did the Trojans now retreat before the Achaeans.
+Glaucus, captain of the Lycians, was the first to rally them, by
+killing Bathycles son of Chalcon who lived in Hellas and was the
+richest man among the Myrmidons. Glaucus turned round suddenly,
+just as Bathycles who was pursuing him was about to lay hold of
+him, and drove his spear right into the middle of his chest,
+whereon he fell heavily to the ground, and the fall of so good a
+man filled the Achaeans with dismay, while the Trojans were
+exultant, and came up in a body round the corpse. Nevertheless
+the Achaeans, mindful of their prowess, bore straight down upon
+them.
+</para>
+
+<para>
+Meriones then killed a helmed warrior of the Trojans, Laogonus
+son of Onetor, who was priest of Jove of Mt. Ida, and was
+honoured by the people as though he were a god. Meriones struck
+him under the jaw and ear, so that life went out of him and the
+darkness of death laid hold upon him. Aeneas then aimed a spear
+at Meriones, hoping to hit him under the shield as he was
+advancing, but Meriones saw it coming and stooped forward to
+avoid it, whereon the spear flew past him and the point stuck in
+the ground, while the butt-end went on quivering till Mars robbed
+it of its force. The spear, therefore, sped from Aeneas's hand in
+vain and fell quivering to the ground. Aeneas was angry and said,
+"Meriones, you are a good dancer, but if I had hit you my spear
+would soon have made an end of you."
+</para>
+
+<para>
+And Meriones answered, "Aeneas, for all your bravery, you will
+not be able to make an end of every one who comes against you.
+You are only a mortal like myself, and if I were to hit you in
+the middle of your shield with my spear, however strong and
+self-confident you may be, I should soon vanquish you, and you
+would yield your life to Hades of the noble steeds."
+</para>
+
+<para>
+On this the son of Menoetius rebuked him and said, "Meriones,
+hero though you be, you should not speak thus; taunting speeches,
+my good friend, will not make the Trojans draw away from the dead
+body; some of them must go under ground first; blows for battle,
+and words for council; fight, therefore, and say nothing."
+</para>
+
+<para>
+He led the way as he spoke and the hero went forward with him.
+As the sound of woodcutters in some forest glade upon the
+mountains--and the thud of their axes is heard afar--even such a
+din now rose from earth-clash of bronze armour and of good
+ox-hide shields, as men smote each other with their swords and
+spears pointed at both ends. A man had need of good eyesight now
+to know Sarpedon, so covered was he from head to foot with spears
+and blood and dust. Men swarmed about the body, as flies that
+buzz round the full milk-pails in spring when they are brimming
+with milk--even so did they gather round Sarpedon; nor did Jove
+turn his keen eyes away for one moment from the fight, but kept
+looking at it all the time, for he was settling how best to kill
+Patroclus, and considering whether Hector should be allowed to
+end him now in the fight round the body of Sarpedon, and strip
+him of his armour, or whether he should let him give yet further
+trouble to the Trojans. In the end, he deemed it best that the
+brave squire of Achilles son of Peleus should drive Hector and
+the Trojans back towards the city and take the lives of many.
+First, therefore, he made Hector turn fainthearted, whereon he
+mounted his chariot and fled, bidding the other Trojans fly also,
+for he saw that the scales of Jove had turned against him.
+Neither would the brave Lycians stand firm; they were dismayed
+when they saw their king lying struck to the heart amid a heap of
+corpses--for when the son of Saturn made the fight wax hot many
+had fallen above him. The Achaeans, therefore stripped the
+gleaming armour from his shoulders and the brave son of Menoetius
+gave it to his men to take to the ships. Then Jove lord of the
+storm-cloud said to Apollo, "Dear Phoebus, go, I pray you, and
+take Sarpedon out of range of the weapons; cleanse the black
+blood from off him, and then bear him a long way off where you
+may wash him in the river, anoint him with ambrosia, and clothe
+him in immortal raiment; this done, commit him to the arms of the
+two fleet messengers, Death, and Sleep, who will carry him
+straightway to the rich land of Lycia, where his brothers and
+kinsmen will inter him, and will raise both mound and pillar to
+his memory, in due honour to the dead."
+</para>
+
+<para>
+Thus he spoke. Apollo obeyed his father's saying, and came down
+from the heights of Ida into the thick of the fight; forthwith he
+took Sarpedon out of range of the weapons, and then bore him a
+long way off, where he washed him in the river, anointed him with
+ambrosia and clothed him in immortal raiment; this done, he
+committed him to the arms of the two fleet messengers, Death, and
+Sleep, who presently set him down in the rich land of Lycia.
+</para>
+
+<para>
+Meanwhile Patroclus, with many a shout to his horses and to
+Automedon, pursued the Trojans and Lycians in the pride and
+foolishness of his heart. Had he but obeyed the bidding of the
+son of Peleus, he would have, escaped death and have been
+scatheless; but the counsels of Jove pass man's understanding; he
+will put even a brave man to flight and snatch victory from his
+grasp, or again he will set him on to fight, as he now did when
+he put a high spirit into the heart of Patroclus.
+</para>
+
+<para>
+Who then first, and who last, was slain by you, O Patroclus, when
+the gods had now called you to meet your doom? First Adrestus,
+Autonous, Echeclus, Perimus the son of Megas, Epistor and
+Melanippus; after these he killed Elasus, Mulius, and Pylartes.
+These he slew, but the rest saved themselves by flight.
+</para>
+
+<para>
+The sons of the Achaeans would now have taken Troy by the hands
+of Patroclus, for his spear flew in all directions, had not
+Phoebus Apollo taken his stand upon the wall to defeat his
+purpose and to aid the Trojans. Thrice did Patroclus charge at an
+angle of the high wall, and thrice did Apollo beat him back,
+striking his shield with his own immortal hands. When Patroclus
+was coming on like a god for yet a fourth time, Apollo shouted to
+him with an awful voice and said, "Draw back, noble Patroclus, it
+is not your lot to sack the city of the Trojan chieftains, nor
+yet will it be that of Achilles who is a far better man than you
+are." On hearing this, Patroclus withdrew to some distance and
+avoided the anger of Apollo.
+</para>
+
+<para>
+Meanwhile Hector was waiting with his horses inside the Scaean
+gates, in doubt whether to drive out again and go on fighting, or
+to call the army inside the gates. As he was thus doubting
+Phoebus Apollo drew near him in the likeness of a young and lusty
+warrior Asius, who was Hector's uncle, being own brother to
+Hecuba, and son of Dymas who lived in Phrygia by the waters of
+the river Sangarius; in his likeness Jove's son Apollo now spoke
+to Hector saying, "Hector, why have you left off fighting? It is
+ill done of you. If I were as much better a man than you, as I am
+worse, you should soon rue your slackness. Drive straight towards
+Patroclus, if so be that Apollo may grant you a triumph over him,
+and you may rule him."
+</para>
+
+<para>
+With this the god went back into the hurly-burly, and Hector bade
+Cebriones drive again into the fight. Apollo passed in among
+them, and struck panic into the Argives, while he gave triumph to
+Hector and the Trojans. Hector let the other Danaans alone and
+killed no man, but drove straight at Patroclus. Patroclus then
+sprang from his chariot to the ground, with a spear in his left
+hand, and in his right a jagged stone as large as his hand could
+hold. He stood still and threw it, nor did it go far without
+hitting some one; the cast was not in vain, for the stone struck
+Cebriones, Hector's charioteer, a bastard son of Priam, as he
+held the reins in his hands. The stone hit him on the forehead
+and drove his brows into his head for the bone was smashed, and
+his eyes fell to the ground at his feet. He dropped dead from his
+chariot as though he were diving, and there was no more life left
+in him. Over him did you then vaunt, O knight Patroclus, saying,
+"Bless my heart, how active he is, and how well he dives. If we
+had been at sea this fellow would have dived from the ship's side
+and brought up as many oysters as the whole crew could stomach,
+even in rough water, for he has dived beautifully off his chariot
+on to the ground. It seems, then, that there are divers also
+among the Trojans."
+</para>
+
+<para>
+As he spoke he flung himself on Cebriones with the spring, as it
+were, of a lion that while attacking a stockyard is himself
+struck in the chest, and his courage is his own bane--even so
+furiously, O Patroclus, did you then spring upon Cebriones.
+Hector sprang also from his chariot to the ground. The pair then
+fought over the body of Cebriones. As two lions fight fiercely on
+some high mountain over the body of a stag that they have killed,
+even so did these two mighty warriors, Patroclus son of Menoetius
+and brave Hector, hack and hew at one another over the corpse of
+Cebriones. Hector would not let him go when he had once got him
+by the head, while Patroclus kept fast hold of his feet, and a
+fierce fight raged between the other Danaans and Trojans. As the
+east and south wind buffet one another when they beat upon some
+dense forest on the mountains--there is beech and ash and
+spreading cornel; the top of the trees roar as they beat on one
+another, and one can hear the boughs cracking and breaking--even
+so did the Trojans and Achaeans spring upon one another and lay
+about each other, and neither side would give way. Many a pointed
+spear fell to ground and many a winged arrow sped from its
+bow-string about the body of Cebriones; many a great stone,
+moreover, beat on many a shield as they fought around his body,
+but there he lay in the whirling clouds of dust, all huge and
+hugely, heedless of his driving now.
+</para>
+
+<para>
+So long as the sun was still high in mid-heaven the weapons of
+either side were alike deadly, and the people fell; but when he
+went down towards the time when men loose their oxen, the
+Achaeans proved to be beyond all forecast stronger, so that they
+drew Cebriones out of range of the darts and tumult of the
+Trojans, and stripped the armour from his shoulders. Then
+Patroclus sprang like Mars with fierce intent and a terrific
+shout upon the Trojans, and thrice did he kill nine men; but as
+he was coming on like a god for a time, then, O Patroclus, was
+the hour of your end approaching, for Phoebus fought you in fell
+earnest. Patroclus did not see him as he moved about in the
+crush, for he was enshrouded in thick darkness, and the god
+struck him from behind on his back and his broad shoulders with
+the flat of his hand, so that his eyes turned dizzy. Phoebus
+Apollo beat the helmet from off his head, and it rolled rattling
+off under the horses' feet, where its horse-hair plumes were all
+begrimed with dust and blood. Never indeed had that helmet fared
+so before, for it had served to protect the head and comely
+forehead of the godlike hero Achilles. Now, however, Zeus
+delivered it over to be worn by Hector. Nevertheless the end of
+Hector also was near. The bronze-shod spear, so great and so
+strong, was broken in the hand of Patroclus, while his shield
+that covered him from head to foot fell to the ground as did also
+the band that held it, and Apollo undid the fastenings of his
+corslet.
+</para>
+
+<para>
+On this his mind became clouded; his limbs failed him, and he
+stood as one dazed; whereon Euphorbus son of Panthous a
+Dardanian, the best spearman of his time, as also the finest
+horseman and fleetest runner, came behind him and struck him in
+the back with a spear, midway between the shoulders. This man as
+soon as ever he had come up with his chariot had dismounted
+twenty men, so proficient was he in all the arts of war--he it
+was, O knight Patroclus, that first drove a weapon into you, but
+he did not quite overpower you. Euphorbus then ran back into the
+crowd, after drawing his ashen spear out of the wound; he would
+not stand firm and wait for Patroclus, unarmed though he now was,
+to attack him; but Patroclus unnerved, alike by the blow the god
+had given him and by the spear-wound, drew back under cover of
+his men in fear for his life. Hector on this, seeing him to be
+wounded and giving ground, forced his way through the ranks, and
+when close up with him struck him in the lower part of the belly
+with a spear, driving the bronze point right through it, so that
+he fell heavily to the ground to the great of the Achaeans. As
+when a lion has fought some fierce wild-boar and worsted him--the
+two fight furiously upon the mountains over some little fountain
+at which they would both drink, and the lion has beaten the boar
+till he can hardly breathe--even so did Hector son of Priam take
+the life of the brave son of Menoetius who had killed so many,
+striking him from close at hand, and vaunting over him the while.
+"Patroclus," said he, "you deemed that you should sack our city,
+rob our Trojan women of their freedom, and carry them off in your
+ships to your own country. Fool; Hector and his fleet horses were
+ever straining their utmost to defend them. I am foremost of all
+the Trojan warriors to stave the day of bondage from off them; as
+for you, vultures shall devour you here. Poor wretch, Achilles
+with all his bravery availed you nothing; and yet I ween when you
+left him he charged you straitly saying, 'Come not back to the
+ships, knight Patroclus, till you have rent the bloodstained
+shirt of murderous Hector about his body. Thus I ween did he
+charge you, and your fool's heart answered him 'yea' within you."
+</para>
+
+<para>
+Then, as the life ebbed out of you, you answered, O knight
+Patroclus: "Hector, vaunt as you will, for Jove the son of Saturn
+and Apollo have vouchsafed you victory; it is they who have
+vanquished me so easily, and they who have stripped the armour
+from my shoulders; had twenty such men as you attacked me, all of
+them would have fallen before my spear. Fate and the son of Leto
+have overpowered me, and among mortal men Euphorbus; you are
+yourself third only in the killing of me. I say further, and lay
+my saying to your heart, you too shall live but for a little
+season; death and the day of your doom are close upon you, and
+they will lay you low by the hand of Achilles son of Aeacus."
+</para>
+
+<para>
+When he had thus spoken his eyes were closed in death, his soul
+left his body and flitted down to the house of Hades, mourning
+its sad fate and bidding farewell to the youth and vigor of its
+manhood. Dead though he was, Hector still spoke to him saying,
+"Patroclus, why should you thus foretell my doom? Who knows but
+Achilles, son of lovely Thetis, may be smitten by my spear and
+die before me?"
+</para>
+
+<para>
+As he spoke he drew the bronze spear from the wound, planting his
+foot upon the body, which he thrust off and let lie on its back.
+He then went spear in hand after Automedon, squire of the fleet
+descendant of Aeacus, for he longed to lay him low, but the
+immortal steeds which the gods had given as a rich gift to Peleus
+bore him swiftly from the field.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK XVII</title>
+
+<para>
+BRAVE Menelaus son of Atreus now came to know that Patroclus had
+fallen, and made his way through the front ranks clad in full
+armour to bestride him. As a cow stands lowing over her first
+calf, even so did yellow-haired Menelaus bestride Patroclus. He
+held his round shield and his spear in front of him, resolute to
+kill any who should dare face him. But the son of Panthous had
+also noted the body, and came up to Menelaus saying, "Menelaus,
+son of Atreus, draw back, leave the body, and let the
+bloodstained spoils be. I was first of the Trojans and their
+brave allies to drive my spear into Patroclus, let me, therefore,
+have my full glory among the Trojans, or I will take aim and kill
+you."
+</para>
+
+<para>
+To this Menelaus answered in great anger "By father Jove,
+boasting is an ill thing. The pard is not more bold, nor the lion
+nor savage wild-boar, which is fiercest and most dauntless of all
+creatures, than are the proud sons of Panthous. Yet Hyperenor did
+not see out the days of his youth when he made light of me and
+withstood me, deeming me the meanest soldier among the Danaans.
+His own feet never bore him back to gladden his wife and parents.
+Even so shall I make an end of you too, if you withstand me; get
+you back into the crowd and do not face me, or it shall be worse
+for you. Even a fool may be wise after the event."
+</para>
+
+<para>
+Euphorbus would not listen, and said, "Now indeed, Menelaus,
+shall you pay for the death of my brother over whom you vaunted,
+and whose wife you widowed in her bridal chamber, while you
+brought grief unspeakable on his parents. I shall comfort these
+poor people if I bring your head and armour and place them in the
+hands of Panthous and noble Phrontis. The time is come when this
+matter shall be fought out and settled, for me or against me."
+</para>
+
+<para>
+As he spoke he struck Menelaus full on the shield, but the spear
+did not go through, for the shield turned its point. Menelaus
+then took aim, praying to father Jove as he did so; Euphorbus was
+drawing back, and Menelaus struck him about the roots of his
+throat, leaning his whole weight on the spear, so as to drive it
+home. The point went clean through his neck, and his armour rang
+rattling round him as he fell heavily to the ground. His hair
+which was like that of the Graces, and his locks so deftly bound
+in bands of silver and gold, were all bedrabbled with blood. As
+one who has grown a fine young olive tree in a clear space where
+there is abundance of water--the plant is full of promise, and
+though the winds beat upon it from every quarter it puts forth
+its white blossoms till the blasts of some fierce hurricane sweep
+down upon it and level it with the ground--even so did Menelaus
+strip the fair youth Euphorbus of his armour after he had slain
+him. Or as some fierce lion upon the mountains in the pride of
+his strength fastens on the finest heifer in a herd as it is
+feeding--first he breaks her neck with his strong jaws, and then
+gorges on her blood and entrails; dogs and shepherds raise a hue
+and cry against him, but they stand aloof and will not come close
+to him, for they are pale with fear--even so no one had the
+courage to face valiant Menelaus. The son of Atreus would have
+then carried off the armour of the son of Panthous with ease, had
+not Phoebus Apollo been angry, and in the guise of Mentes chief
+of the Cicons incited Hector to attack him. "Hector," said he,
+"you are now going after the horses of the noble son of Aeacus,
+but you will not take them; they cannot be kept in hand and
+driven by mortal man, save only by Achilles, who is son to an
+immortal mother. Meanwhile Menelaus son of Atreus has bestridden
+the body of Patroclus and killed the noblest of the Trojans,
+Euphorbus son of Panthous, so that he can fight no more."
+</para>
+
+<para>
+The god then went back into the toil and turmoil, but the soul of
+Hector was darkened with a cloud of grief; he looked along the
+ranks and saw Euphorbus lying on the ground with the blood still
+flowing from his wound, and Menelaus stripping him of his armour.
+On this he made his way to the front like a flame of fire, clad
+in his gleaming armour, and crying with a loud voice. When the
+son of Atreus heard him, he said to himself in his dismay, "Alas!
+what shall I do? I may not let the Trojans take the armour of
+Patroclus who has fallen fighting on my behalf, lest some Danaan
+who sees me should cry shame upon me. Still if for my honour's
+sake I fight Hector and the Trojans single-handed, they will
+prove too many for me, for Hector is bringing them up in force.
+Why, however, should I thus hesitate? When a man fights in
+despite of heaven with one whom a god befriends, he will soon rue
+it. Let no Danaan think ill of me if I give place to Hector, for
+the hand of heaven is with him. Yet, if I could find Ajax, the
+two of us would fight Hector and heaven too, if we might only
+save the body of Patroclus for Achilles son of Peleus. This, of
+many evils would be the least."
+</para>
+
+<para>
+While he was thus in two minds, the Trojans came up to him with
+Hector at their head; he therefore drew back and left the body,
+turning about like some bearded lion who is being chased by dogs
+and men from a stockyard with spears and hue and cry, whereon he
+is daunted and slinks sulkily off--even so did Menelaus son of
+Atreus turn and leave the body of Patroclus. When among the body
+of his men, he looked around for mighty Ajax son of Telamon, and
+presently saw him on the extreme left of the fight, cheering on
+his men and exhorting them to keep on fighting, for Phoebus
+Apollo had spread a great panic among them. He ran up to him and
+said, "Ajax, my good friend, come with me at once to dead
+Patroclus, if so be that we may take the body to Achilles--as for
+his armour, Hector already has it."
+</para>
+
+<para>
+These words stirred the heart of Ajax, and he made his way among
+the front ranks, Menelaus going with him. Hector had stripped
+Patroclus of his armour, and was dragging him away to cut off his
+head and take the body to fling before the dogs of Troy. But Ajax
+came up with his shield like wall before him, on which Hector
+withdrew under shelter of his men, and sprang on to his chariot,
+giving the armour over to the Trojans to take to the city, as a
+great trophy for himself; Ajax, therefore, covered the body of
+Patroclus with his broad shield and bestrode him; as a lion
+stands over his whelps if hunters have come upon him in a forest
+when he is with his little ones--in the pride and fierceness of
+his strength he draws his knit brows down till they cover his
+eyes--even so did Ajax bestride the body of Patroclus, and by his
+side stood Menelaus son of Atreus, nursing great sorrow in his
+heart.
+</para>
+
+<para>
+Then Glaucus son of Hippolochus looked fiercely at Hector and
+rebuked him sternly. "Hector," said he, "you make a brave show,
+but in fight you are sadly wanting. A runaway like yourself has
+no claim to so great a reputation. Think how you may now save
+your town and citadel by the hands of your own people born in
+Ilius; for you will get no Lycians to fight for you, seeing what
+thanks they have had for their incessant hardships. Are you
+likely, sir, to do anything to help a man of less note, after
+leaving Sarpedon, who was at once your guest and comrade in arms,
+to be the spoil and prey of the Danaans? So long as he lived he
+did good service both to your city and yourself; yet you had no
+stomach to save his body from the dogs. If the Lycians will
+listen to me, they will go home and leave Troy to its fate. If
+the Trojans had any of that daring fearless spirit which lays
+hold of men who are fighting for their country and harassing
+those who would attack it, we should soon bear off Patroclus into
+Ilius. Could we get this dead man away and bring him into the
+city of Priam, the Argives would readily give up the armour of
+Sarpedon, and we should get his body to boot. For he whose squire
+has been now killed is the foremost man at the ships of the
+Achaeans--he and his close-fighting followers. Nevertheless you
+dared not make a stand against Ajax, nor face him, eye to eye,
+with battle all round you, for he is a braver man than you are."
+</para>
+
+<para>
+Hector scowled at him and answered, "Glaucus, you should know
+better. I have held you so far as a man of more understanding
+than any in all Lycia, but now I despise you for saying that I am
+afraid of Ajax. I fear neither battle nor the din of chariots,
+but Jove's will is stronger than ours; Jove at one time makes
+even a strong man draw back and snatches victory from his grasp,
+while at another he will set him on to fight. Come hither then,
+my friend, stand by me and see indeed whether I shall play the
+coward the whole day through as you say, or whether I shall not
+stay some even of the boldest Danaans from fighting round the
+body of Patroclus."
+</para>
+
+<para>
+As he spoke he called loudly on the Trojans saying, "Trojans,
+Lycians, and Dardanians, fighters in close combat, be men, my
+friends, and fight might and main, while I put on the goodly
+armour of Achilles, which I took when I killed Patroclus."
+</para>
+
+<para>
+With this Hector left the fight, and ran full speed after his men
+who were taking the armour of Achilles to Troy, but had not yet
+got far. Standing for a while apart from the woeful fight, he
+changed his armour. His own he sent to the strong city of Ilius
+and to the Trojans, while he put on the immortal armour of the
+son of Peleus, which the gods had given to Peleus, who in his age
+gave it to his son; but the son did not grow old in his father's
+armour.
+</para>
+
+<para>
+When Jove, lord of the storm-cloud, saw Hector standing aloof and
+arming himself in the armour of the son of Peleus, he wagged his
+head and muttered to himself saying, "A! poor wretch, you arm in
+the armour of a hero, before whom many another trembles, and you
+reck nothing of the doom that is already close upon you. You have
+killed his comrade so brave and strong, but it was not well that
+you should strip the armour from his head and shoulders. I do
+indeed endow you with great might now, but as against this you
+shall not return from battle to lay the armour of the son of
+Peleus before Andromache."
+</para>
+
+<para>
+The son of Saturn bowed his portentous brows, and Hector fitted
+the armour to his body, while terrible Mars entered into him, and
+filled his whole body with might and valour. With a shout he
+strode in among the allies, and his armour flashed about him so
+that he seemed to all of them like the great son of Peleus
+himself. He went about among them and cheered them on--Mesthles,
+Glaucus, Medon, Thersilochus, Asteropaeus, Deisenor and
+Hippothous, Phorcys, Chromius and Ennomus the augur. All these
+did he exhort saying, "Hear me, allies from other cities who are
+here in your thousands, it was not in order to have a crowd about
+me that I called you hither each from his several city, but that
+with heart and soul you might defend the wives and little ones of
+the Trojans from the fierce Achaeans. For this do I oppress my
+people with your food and the presents that make you rich.
+Therefore turn, and charge at the foe, to stand or fall as is the
+game of war; whoever shall bring Patroclus, dead though he be,
+into the hands of the Trojans, and shall make Ajax give way
+before him, I will give him one half of the spoils while I keep
+the other. He will thus share like honour with myself."
+</para>
+
+<para>
+When he had thus spoken they charged full weight upon the Danaans
+with their spears held out before them, and the hopes of each ran
+high that he should force Ajax son of Telamon to yield up the
+body--fools that they were, for he was about to take the lives of
+many. Then Ajax said to Menelaus, "My good friend Menelaus, you
+and I shall hardly come out of this fight alive. I am less
+concerned for the body of Patroclus, who will shortly become meat
+for the dogs and vultures of Troy, than for the safety of my own
+head and yours. Hector has wrapped us round in a storm of battle
+from every quarter, and our destruction seems now certain. Call
+then upon the princes of the Danaans if there is any who can hear
+us."
+</para>
+
+<para>
+Menelaus did as he said, and shouted to the Danaans for help at
+the top of his voice. "My friends," he cried, "princes and
+counsellors of the Argives, all you who with Agamemnon and
+Menelaus drink at the public cost, and give orders each to his
+own people as Jove vouchsafes him power and glory, the fight is
+so thick about me that I cannot distinguish you severally; come
+on, therefore, every man unbidden, and think it shame that
+Patroclus should become meat and morsel for Trojan hounds."
+</para>
+
+<para>
+Fleet Ajax son of Oileus heard him and was first to force his way
+through the fight and run to help him. Next came Idomeneus and
+Meriones his esquire, peer of murderous Mars. As for the others
+that came into the fight after these, who of his own self could
+name them?
+</para>
+
+<para>
+The Trojans with Hector at their head charged in a body. As a
+great wave that comes thundering in at the mouth of some
+heaven-born river, and the rocks that jut into the sea ring with
+the roar of the breakers that beat and buffet them--even with
+such a roar did the Trojans come on; but the Achaeans in
+singleness of heart stood firm about the son of Menoetius, and
+fenced him with their bronze shields. Jove, moreover, hid the
+brightness of their helmets in a thick cloud, for he had borne no
+grudge against the son of Menoetius while he was still alive and
+squire to the descendant of Aeacus; therefore he was loth to let
+him fall a prey to the dogs of his foes the Trojans, and urged
+his comrades on to defend him.
+</para>
+
+<para>
+At first the Trojans drove the Achaeans back, and they withdrew
+from the dead man daunted. The Trojans did not succeed in killing
+any one, nevertheless they drew the body away. But the Achaeans
+did not lose it long, for Ajax, foremost of all the Danaans after
+the son of Peleus alike in stature and prowess, quickly rallied
+them and made towards the front like a wild boar upon the
+mountains when he stands at bay in the forest glades and routs
+the hounds and lusty youths that have attacked him--even so did
+Ajax son of Telamon passing easily in among the phalanxes of the
+Trojans, disperse those who had bestridden Patroclus and were
+most bent on winning glory by dragging him off to their city. At
+this moment Hippothous brave son of the Pelasgian Lethus, in his
+zeal for Hector and the Trojans, was dragging the body off by the
+foot through the press of the fight, having bound a strap round
+the sinews near the ancle; but a mischief soon befell him from
+which none of those could save him who would have gladly done so,
+for the son of Telamon sprang forward and smote him on his
+bronze-cheeked helmet. The plumed headpiece broke about the point
+of the weapon, struck at once by the spear and by the strong hand
+of Ajax, so that the bloody brain came oozing out through the
+crest-socket. His strength then failed him and he let Patroclus'
+foot drop from his hand, as he fell full length dead upon the
+body; thus he died far from the fertile land of Larissa, and
+never repaid his parents the cost of bringing him up, for his
+life was cut short early by the spear of mighty Ajax. Hector then
+took aim at Ajax with a spear, but he saw it coming and just
+managed to avoid it; the spear passed on and struck Schedius son
+of noble Iphitus, captain of the Phoceans, who dwelt in famed
+Panopeus and reigned over much people; it struck him under the
+middle of the collar-bone the bronze point went right through
+him, coming out at the bottom of his shoulder-blade, and his
+armour rang rattling round him as he fell heavily to the ground.
+Ajax in his turn struck noble Phorcys son of Phaenops in the
+middle of the belly as he was bestriding Hippothous, and broke
+the plate of his cuirass; whereon the spear tore out his entrails
+and he clutched the ground in his palm as he fell to earth.
+Hector and those who were in the front rank then gave ground,
+while the Argives raised a loud cry of triumph, and drew off the
+bodies of Phorcys and Hippothous which they stripped presently of
+their armour.
+</para>
+
+<para>
+The Trojans would now have been worsted by the brave Achaeans and
+driven back to Ilius through their own cowardice, while the
+Argives, so great was their courage and endurance, would have
+achieved a triumph even against the will of Jove, if Apollo had
+not roused Aeneas, in the likeness of Periphas son of Epytus, an
+attendant who had grown old in the service of Aeneas' aged
+father, and was at all times devoted to him. In his likeness,
+then, Apollo said, "Aeneas, can you not manage, even though
+heaven be against us, to save high Ilius? I have known men, whose
+numbers, courage, and self-reliance have saved their people in
+spite of Jove, whereas in this case he would much rather give
+victory to us than to the Danaans, if you would only fight
+instead of being so terribly afraid."
+</para>
+
+<para>
+Aeneas knew Apollo when he looked straight at him, and shouted to
+Hector saying, "Hector and all other Trojans and allies, shame on
+us if we are beaten by the Achaeans and driven back to Ilius
+through our own cowardice. A god has just come up to me and told
+me that Jove the supreme disposer will be with us. Therefore let
+us make for the Danaans, that it may go hard with them ere they
+bear away dead Patroclus to the ships."
+</para>
+
+<para>
+As he spoke he sprang out far in front of the others, who then
+rallied and again faced the Achaeans. Aeneas speared Leiocritus
+son of Arisbas, a valiant follower of Lycomedes, and Lycomedes
+was moved with pity as he saw him fall; he therefore went close
+up, and speared Apisaon son of Hippasus shepherd of his people in
+the liver under the midriff, so that he died; he had come from
+fertile Paeonia and was the best man of them all after
+Asteropaeus. Asteropaeus flew forward to avenge him and attack
+the Danaans, but this might no longer be, inasmuch as those about
+Patroclus were well covered by their shields, and held their
+spears in front of them, for Ajax had given them strict orders
+that no man was either to give ground, or to stand out before the
+others, but all were to hold well together about the body and
+fight hand to hand. Thus did huge Ajax bid them, and the earth
+ran red with blood as the corpses fell thick on one another alike
+on the side of the Trojans and allies, and on that of the
+Danaans; for these last, too, fought no bloodless fight though
+many fewer of them perished, through the care they took to defend
+and stand by one another.
+</para>
+
+<para>
+Thus did they fight as it were a flaming fire; it seemed as
+though it had gone hard even with the sun and moon, for they were
+hidden over all that part where the bravest heroes were fighting
+about the dead son of Menoetius, whereas the other Danaans and
+Achaeans fought at their ease in full daylight with brilliant
+sunshine all round them, and there was not a cloud to be seen
+neither on plain nor mountain. These last moreover would rest for
+a while and leave off fighting, for they were some distance apart
+and beyond the range of one another's weapons, whereas those who
+were in the thick of the fray suffered both from battle and
+darkness. All the best of them were being worn out by the great
+weight of their armour, but the two valiant heroes, Thrasymedes
+and Antilochus, had not yet heard of the death of Patroclus, and
+believed him to be still alive and leading the van against the
+Trojans; they were keeping themselves in reserve against the
+death or rout of their own comrades, for so Nestor had ordered
+when he sent them from the ships into battle.
+</para>
+
+<para>
+Thus through the livelong day did they wage fierce war, and the
+sweat of their toil rained ever on their legs under them, and on
+their hands and eyes, as they fought over the squire of the fleet
+son of Peleus. It was as when a man gives a great ox-hide all
+drenched in fat to his men, and bids them stretch it; whereon
+they stand round it in a ring and tug till the moisture leaves
+it, and the fat soaks in for the many that pull at it, and it is
+well stretched--even so did the two sides tug the dead body
+hither and thither within the compass of but a little space--the
+Trojans steadfastly set on dragging it into Ilius, while the
+Achaeans were no less so on taking it to their ships; and fierce
+was the fight between them. Not Mars himself the lord of hosts,
+nor yet Minerva, even in their fullest fury could make light of
+such a battle.
+</para>
+
+<para>
+Such fearful turmoil of men and horses did Jove on that day
+ordain round the body of Patroclus. Meanwhile Achilles did not
+know that he had fallen, for the fight was under the wall of Troy
+a long way off the ships. He had no idea, therefore, that
+Patroclus was dead, and deemed that he would return alive as soon
+as he had gone close up to the gates. He knew that he was not to
+sack the city neither with nor without himself, for his mother
+had often told him this when he had sat alone with her, and she
+had informed him of the counsels of great Jove. Now, however, she
+had not told him how great a disaster had befallen him in the
+death of the one who was far dearest to him of all his comrades.
+</para>
+
+<para>
+The others still kept on charging one another round the body with
+their pointed spears and killing each other. Then would one say,
+"My friends, we can never again show our faces at the ships--
+better, and greatly better, that earth should open and swallow us
+here in this place, than that we should let the Trojans have the
+triumph of bearing off Patroclus to their city."
+</para>
+
+<para>
+The Trojans also on their part spoke to one another saying,
+"Friends, though we fall to a man beside this body, let none
+shrink from fighting." With such words did they exhort each
+other. They fought and fought, and an iron clank rose through the
+void air to the brazen vault of heaven. The horses of the
+descendant of Aeacus stood out of the fight and wept when they
+heard that their driver had been laid low by the hand of
+murderous Hector. Automedon, valiant son of Diores, lashed them
+again and again; many a time did he speak kindly to them, and
+many a time did he upbraid them, but they would neither go back
+to the ships by the waters of the broad Hellespont, nor yet into
+battle among the Achaeans; they stood with their chariot stock
+still, as a pillar set over the tomb of some dead man or woman,
+and bowed their heads to the ground. Hot tears fell from their
+eyes as they mourned the loss of their charioteer, and their
+noble manes drooped all wet from under the yokestraps on either
+side the yoke.
+</para>
+
+<para>
+The son of Saturn saw them and took pity upon their sorrow. He
+wagged his head, and muttered to himself, saying, "Poor things,
+why did we give you to King Peleus who is a mortal, while you are
+yourselves ageless and immortal? Was it that you might share the
+sorrows that befall mankind? for of all creatures that live and
+move upon the earth there is none so pitiable as he is--still,
+Hector son of Priam shall drive neither you nor your chariot. I
+will not have it. It is enough that he should have the armour
+over which he vaunts so vainly. Furthermore I will give you
+strength of heart and limb to bear Automedon safely to the ships
+from battle, for I shall let the Trojans triumph still further,
+and go on killing till they reach the ships; whereon night shall
+fall and darkness overshadow the land."
+</para>
+
+<para>
+As he spoke he breathed heart and strength into the horses so
+that they shook the dust from out of their manes, and bore their
+chariot swiftly into the fight that raged between Trojans and
+Achaeans. Behind them fought Automedon full of sorrow for his
+comrade, as a vulture amid a flock of geese. In and out, and here
+and there, full speed he dashed amid the throng of the Trojans,
+but for all the fury of his pursuit he killed no man, for he
+could not wield his spear and keep his horses in hand when alone
+in the chariot; at last, however, a comrade, Alcimedon, son of
+Laerces son of Haemon caught sight of him and came up behind his
+chariot. "Automedon," said he, "what god has put this folly into
+your heart and robbed you of your right mind, that you fight the
+Trojans in the front rank single-handed? He who was your comrade
+is slain, and Hector plumes himself on being armed in the armour
+of the descendant of Aeacus."
+</para>
+
+<para>
+Automedon son of Diores answered, "Alcimedon, there is no one
+else who can control and guide the immortal steeds so well as you
+can, save only Patroclus--while he was alive--peer of gods in
+counsel. Take then the whip and reins, while I go down from the
+car and fight."
+</para>
+
+<para>
+Alcimedon sprang on to the chariot, and caught up the whip and
+reins, while Automedon leaped from off the car. When Hector saw
+him he said to Aeneas who was near him, "Aeneas, counsellor of
+the mail-clad Trojans, I see the steeds of the fleet son of
+Aeacus come into battle with weak hands to drive them. I am sure,
+if you think well, that we might take them; they will not dare
+face us if we both attack them."
+</para>
+
+<para>
+The valiant son of Anchises was of the same mind, and the pair
+went right on, with their shoulders covered under shields of
+tough dry ox-hide, overlaid with much bronze. Chromius and Aretus
+went also with them, and their hearts beat high with hope that
+they might kill the men and capture the horses--fools that they
+were, for they were not to return scatheless from their meeting
+with Automedon, who prayed to father Jove and was forthwith
+filled with courage and strength abounding. He turned to his
+trusty comrade Alcimedon and said, "Alcimedon, keep your horses
+so close up that I may feel their breath upon my back; I doubt
+that we shall not stay Hector son of Priam till he has killed us
+and mounted behind the horses; he will then either spread panic
+among the ranks of the Achaeans, or himself be killed among the
+foremost."
+</para>
+
+<para>
+On this he cried out to the two Ajaxes and Menelaus, "Ajaxes
+captains of the Argives, and Menelaus, give the dead body over to
+them that are best able to defend it, and come to the rescue of
+us living; for Hector and Aeneas who are the two best men among
+the Trojans, are pressing us hard in the full tide of war.
+Nevertheless the issue lies on the lap of heaven, I will
+therefore hurl my spear and leave the rest to Jove."
+</para>
+
+<para>
+He poised and hurled as he spoke, whereon the spear struck the
+round shield of Aretus, and went right through it for the shield
+stayed it not, so that it was driven through his belt into the
+lower part of his belly. As when some sturdy youth, axe in hand,
+deals his blow behind the horns of an ox and severs the tendons
+at the back of its neck so that it springs forward and then
+drops, even so did Aretus give one bound and then fall on his
+back the spear quivering in his body till it made an end of him.
+Hector then aimed a spear at Automedon but he saw it coming and
+stooped forward to avoid it, so that it flew past him and the
+point stuck in the ground, while the butt-end went on quivering
+till Mars robbed it of its force. They would then have fought
+hand to hand with swords had not the two Ajaxes forced their way
+through the crowd when they heard their comrade calling, and
+parted them for all their fury--for Hector, Aeneas, and Chromius
+were afraid and drew back, leaving Aretus to lie there struck to
+the heart. Automedon, peer of fleet Mars, then stripped him of
+his armour and vaunted over him saying, "I have done little to
+assuage my sorrow for the son of Menoetius, for the man I have
+killed is not so good as he was."
+</para>
+
+<para>
+As he spoke he took the blood-stained spoils and laid them upon
+his chariot; then he mounted the car with his hands and feet all
+steeped in gore as a lion that has been gorging upon a bull.
+</para>
+
+<para>
+And now the fierce groanful fight again raged about Patroclus,
+for Minerva came down from heaven and roused its fury by the
+command of far-seeing Jove, who had changed his mind and sent her
+to encourage the Danaans. As when Jove bends his bright bow in
+heaven in token to mankind either of war or of the chill storms
+that stay men from their labour and plague the flocks--even so,
+wrapped in such radiant raiment, did Minerva go in among the host
+and speak man by man to each. First she took the form and voice
+of Phoenix and spoke to Menelaus son of Atreus, who was standing
+near her. "Menelaus," said she, "it will be shame and dishonour
+to you, if dogs tear the noble comrade of Achilles under the
+walls of Troy. Therefore be staunch, and urge your men to be so
+also."
+</para>
+
+<para>
+Menelaus answered, "Phoenix, my good old friend, may Minerva
+vouchsafe me strength and keep the darts from off me, for so
+shall I stand by Patroclus and defend him; his death has gone to
+my heart, but Hector is as a raging fire and deals his blows
+without ceasing, for Jove is now granting him a time of triumph."
+</para>
+
+<para>
+Minerva was pleased at his having named herself before any of the
+other gods. Therefore she put strength into his knees and
+shoulders, and made him as bold as a fly, which, though driven
+off will yet come again and bite if it can, so dearly does it
+love man's blood--even so bold as this did she make him as he
+stood over Patroclus and threw his spear. Now there was among the
+Trojans a man named Podes, son of Eetion, who was both rich and
+valiant. Hector held him in the highest honour for he was his
+comrade and boon companion; the spear of Menelaus struck this man
+in the girdle just as he had turned in flight, and went right
+through him. Whereon he fell heavily forward, and Menelaus son of
+Atreus drew off his body from the Trojans into the ranks of his
+own people.
+</para>
+
+<para>
+Apollo then went up to Hector and spurred him on to fight, in the
+likeness of Phaenops son of Asius who lived in Abydos and was the
+most favoured of all Hector's guests. In his likeness Apollo
+said, "Hector, who of the Achaeans will fear you henceforward now
+that you have quailed before Menelaus who has ever been rated
+poorly as a soldier? Yet he has now got a corpse away from the
+Trojans single-handed, and has slain your own true comrade, a man
+brave among the foremost, Podes son of Eetion."
+</para>
+
+<para>
+A dark cloud of grief fell upon Hector as he heard, and he made
+his way to the front clad in full armour. Thereon the son of
+Saturn seized his bright tasselled aegis, and veiled Ida in
+cloud: he sent forth his lightnings and his thunders, and as he
+shook his aegis he gave victory to the Trojans and routed the
+Achaeans.
+</para>
+
+<para>
+The panic was begun by Peneleos the Boeotian, for while keeping
+his face turned ever towards the foe he had been hit with a spear
+on the upper part of the shoulder; a spear thrown by Polydamas
+had grazed the top of the bone, for Polydamas had come up to him
+and struck him from close at hand. Then Hector in close combat
+struck Leitus son of noble Alectryon in the hand by the wrist,
+and disabled him from fighting further. He looked about him in
+dismay, knowing that never again should he wield spear in battle
+with the Trojans. While Hector was in pursuit of Leitus,
+Idomeneus struck him on the breastplate over his chest near the
+nipple; but the spear broke in the shaft, and the Trojans cheered
+aloud. Hector then aimed at Idomeneus son of Deucalion as he was
+standing on his chariot, and very narrowly missed him, but the
+spear hit Coiranus, a follower and charioteer of Meriones who had
+come with him from Lyctus. Idomeneus had left the ships on foot
+and would have afforded a great triumph to the Trojans if
+Coiranus had not driven quickly up to him, he therefore brought
+life and rescue to Idomeneus, but himself fell by the hand of
+murderous Hector. For Hector hit him on the jaw under the ear;
+the end of the spear drove out his teeth and cut his tongue in
+two pieces, so that he fell from his chariot and let the reins
+fall to the ground. Meriones gathered them up from the ground and
+took them into his own hands, then he said to Idomeneus, "Lay on,
+till you get back to the ships, for you must see that the day is
+no longer ours."
+</para>
+
+<para>
+On this Idomeneus lashed the horses to the ships, for fear had
+taken hold upon him.
+</para>
+
+<para>
+Ajax and Menelaus noted how Jove had turned the scale in favour
+of the Trojans, and Ajax was first to speak. "Alas," said he,
+"even a fool may see that father Jove is helping the Trojans. All
+their weapons strike home; no matter whether it be a brave man or
+a coward that hurls them, Jove speeds all alike, whereas ours
+fall each one of them without effect. What, then, will be best
+both as regards rescuing the body, and our return to the joy of
+our friends who will be grieving as they look hitherwards; for
+they will make sure that nothing can now check the terrible hands
+of Hector, and that he will fling himself upon our ships. I wish
+that some one would go and tell the son of Peleus at once, for I
+do not think he can have yet heard the sad news that the dearest
+of his friends has fallen. But I can see not a man among the
+Achaeans to send, for they and their chariots are alike hidden in
+darkness. O father Jove, lift this cloud from over the sons of
+the Achaeans; make heaven serene, and let us see; if you will
+that we perish, let us fall at any rate by daylight."
+</para>
+
+<para>
+Father Jove heard him and had compassion upon his tears.
+Forthwith he chased away the cloud of darkness, so that the sun
+shone out and all the fighting was revealed. Ajax then said to
+Menelaus, "Look, Menelaus, and if Antilochus son of Nestor be
+still living, send him at once to tell Achilles that by far the
+dearest to him of all his comrades has fallen."
+</para>
+
+<para>
+Menelaus heeded his words and went his way as a lion from a
+stockyard--the lion is tired of attacking the men and hounds, who
+keep watch the whole night through and will not let him feast on
+the fat of their herd. In his lust of meat he makes straight at
+them but in vain, for darts from strong hands assail him, and
+burning brands which daunt him for all his hunger, so in the
+morning he slinks sulkily away--even so did Menelaus sorely
+against his will leave Patroclus, in great fear lest the Achaeans
+should be driven back in rout and let him fall into the hands of
+the foe. He charged Meriones and the two Ajaxes straitly saying,
+"Ajaxes and Meriones, leaders of the Argives, now indeed remember
+how good Patroclus was; he was ever courteous while alive, bear
+it in mind now that he is dead."
+</para>
+
+<para>
+With this Menelaus left them, looking round him as keenly as an
+eagle, whose sight they say is keener than that of any other
+bird--however high he may be in the heavens, not a hare that runs
+can escape him by crouching under bush or thicket, for he will
+swoop down upon it and make an end of it--even so, O Menelaus,
+did your keen eyes range round the mighty host of your followers
+to see if you could find the son of Nestor still alive. Presently
+Menelaus saw him on the extreme left of the battle cheering on
+his men and exhorting them to fight boldly. Menelaus went up to
+him and said, "Antilochus, come here and listen to sad news,
+which I would indeed were untrue. You must see with your own eyes
+that heaven is heaping calamity upon the Danaans, and giving
+victory to the Trojans. Patroclus has fallen, who was the bravest
+of the Achaeans, and sorely will the Danaans miss him. Run
+instantly to the ships and tell Achilles, that he may come to
+rescue the body and bear it to the ships. As for the armour,
+Hector already has it."
+</para>
+
+<para>
+Antilochus was struck with horror. For a long time he was
+speechless; his eyes filled with tears and he could find no
+utterance, but he did as Menelaus had said, and set off running
+as soon as he had given his armour to a comrade, Laodocus, who
+was wheeling his horses round, close beside him.
+</para>
+
+<para>
+Thus, then, did he run weeping from the field, to carry the bad
+news to Achilles son of Peleus. Nor were you, O Menelaus, minded
+to succour his harassed comrades, when Antilochus had left the
+Pylians--and greatly did they miss him--but he sent them noble
+Thrasymedes, and himself went back to Patroclus. He came running
+up to the two Ajaxes and said, "I have sent Antilochus to the
+ships to tell Achilles, but rage against Hector as he may, he
+cannot come, for he cannot fight without armour. What then will
+be our best plan both as regards rescuing the dead, and our own
+escape from death amid the battle-cries of the Trojans?"
+</para>
+
+<para>
+Ajax answered, "Menelaus, you have said well: do you, then, and
+Meriones stoop down, raise the body, and bear it out of the fray,
+while we two behind you keep off Hector and the Trojans, one in
+heart as in name, and long used to fighting side by side with one
+another."
+</para>
+
+<para>
+On this Menelaus and Meriones took the dead man in their arms and
+lifted him high aloft with a great effort. The Trojan host raised
+a hue and cry behind them when they saw the Achaeans bearing the
+body away, and flew after them like hounds attacking a wounded
+boar at the loo of a band of young huntsmen. For a while the
+hounds fly at him as though they would tear him in pieces, but
+now and again he turns on them in a fury, scaring and scattering
+them in all directions--even so did the Trojans for a while
+charge in a body, striking with sword and with spears pointed ai
+both the ends, but when the two Ajaxes faced them and stood at
+bay, they would turn pale and no man dared press on to fight
+further about the dead.
+</para>
+
+<para>
+In this wise did the two heroes strain every nerve to bear the
+body to the ships out of the fight. The battle raged round them
+like fierce flames that when once kindled spread like wildfire
+over a city, and the houses fall in the glare of its burning--
+even such was the roar and tramp of men and horses that pursued
+them as they bore Patroclus from the field. Or as mules that put
+forth all their strength to draw some beam or great piece of
+ship's timber down a rough mountain-track, and they pant and
+sweat as they, go even so did Menelaus and pant and sweat as they
+bore the body of Patroclus. Behind them the two Ajaxes held
+stoutly out. As some wooded mountain-spur that stretches across a
+plain will turn water and check the flow even of a great river,
+nor is there any stream strong enough to break through it--even
+so did the two Ajaxes face the Trojans and stem the tide of their
+fighting though they kept pouring on towards them and foremost
+among them all was Aeneas son of Anchises with valiant Hector. As
+a flock of daws or starlings fall to screaming and chattering
+when they see a falcon, foe to all small birds, come soaring near
+them, even so did the Achaean youth raise a babel of cries as
+they fled before Aeneas and Hector, unmindful of their former
+prowess. In the rout of the Danaans much goodly armour fell round
+about the trench, and of fighting there was no end.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK XVIII</title>
+
+<para>
+THUS then did they fight as it were a flaming fire. Meanwhile the
+fleet runner Antilochus, who had been sent as messenger, reached
+Achilles, and found him sitting by his tall ships and boding that
+which was indeed too surely true. "Alas," said he to himself in
+the heaviness of his heart, "why are the Achaeans again scouring
+the plain and flocking towards the ships? Heaven grant the gods
+be not now bringing that sorrow upon me of which my mother Thetis
+spoke, saying that while I was yet alive the bravest of the
+Myrmidons should fall before the Trojans, and see the light of
+the sun no longer. I fear the brave son of Menoetius has fallen
+through his own daring and yet I bade him return to the ships as
+soon as he had driven back those that were bringing fire against
+them, and not join battle with Hector."
+</para>
+
+<para>
+As he was thus pondering, the son of Nestor came up to him and
+told his sad tale, weeping bitterly the while. "Alas," he cried,
+"son of noble Peleus, I bring you bad tidings, would indeed that
+they were untrue. Patroclus has fallen, and a fight is raging
+about his naked body--for Hector holds his armour."
+</para>
+
+<para>
+A dark cloud of grief fell upon Achilles as he listened. He
+filled both hands with dust from off the ground, and poured it
+over his head, disfiguring his comely face, and letting the
+refuse settle over his shirt so fair and new. He flung himself
+down all huge and hugely at full length, and tore his hair with
+his hands. The bondswomen whom Achilles and Patroclus had taken
+captive screamed aloud for grief, beating their breasts, and with
+their limbs failing them for sorrow. Antilochus bent over him the
+while, weeping and holding both his hands as he lay groaning for
+he feared that he might plunge a knife into his own throat. Then
+Achilles gave a loud cry and his mother heard him as she was
+sitting in the depths of the sea by the old man her father,
+whereon she screamed, and all the goddesses daughters of Nereus
+that dwelt at the bottom of the sea, came gathering round her.
+There were Glauce, Thalia and Cymodoce, Nesaia, Speo, Thoe and
+dark-eyed Halie, Cymothoe, Actaea and Limnorea, Melite, Iaera,
+Amphithoe and Agave, Doto and Proto, Pherusa and Dynamene,
+Dexamene, Amphinome and Callianeira, Doris, Panope, and the
+famous sea-nymph Galatea, Nemertes, Apseudes and Callianassa.
+There were also Clymene, Ianeira and Ianassa, Maera, Oreithuia
+and Amatheia of the lovely locks, with other Nereids who dwell in
+the depths of the sea. The crystal cave was filled with their
+multitude and they all beat their breasts while Thetis led them
+in their lament.
+</para>
+
+<para>
+"Listen," she cried, "sisters, daughters of Nereus, that you may
+hear the burden of my sorrows. Alas, woe is me, woe in that I
+have borne the most glorious of offspring. I bore him fair and
+strong, hero among heroes, and he shot up as a sapling; I tended
+him as a plant in a goodly garden, and sent him with his ships to
+Ilius to fight the Trojans, but never shall I welcome him back to
+the house of Peleus. So long as he lives to look upon the light
+of the sun he is in heaviness, and though I go to him I cannot
+help him. Nevertheless I will go, that I may see my dear son and
+learn what sorrow has befallen him though he is still holding
+aloof from battle."
+</para>
+
+<para>
+She left the cave as she spoke, while the others followed weeping
+after, and the waves opened a path before them. When they reached
+the rich plain of Troy, they came up out of the sea in a long
+line on to the sands, at the place where the ships of the
+Myrmidons were drawn up in close order round the tents of
+Achilles. His mother went up to him as he lay groaning; she laid
+her hand upon his head and spoke piteously, saying, "My son, why
+are you thus weeping? What sorrow has now befallen you? Tell me;
+hide it not from me. Surely Jove has granted you the prayer you
+made him, when you lifted up your hands and besought him that the
+Achaeans might all of them be pent up at their ships, and rue it
+bitterly in that you were no longer with them."
+</para>
+
+<para>
+Achilles groaned and answered, "Mother, Olympian Jove has indeed
+vouchsafed me the fulfilment of my prayer, but what boots it to
+me, seeing that my dear comrade Patroclus has fallen--he whom I
+valued more than all others, and loved as dearly as my own life?
+I have lost him; aye, and Hector when he had killed him stripped
+the wondrous armour, so glorious to behold, which the gods gave
+to Peleus when they laid you in the couch of a mortal man. Would
+that you were still dwelling among the immortal sea-nymphs, and
+that Peleus had taken to himself some mortal bride. For now you
+shall have grief infinite by reason of the death of that son whom
+you can never welcome home--nay, I will not live nor go about
+among mankind unless Hector fall by my spear, and thus pay me for
+having slain Patroclus son of Menoetius."
+</para>
+
+<para>
+Thetis wept and answered, "Then, my son, is your end near at
+hand--for your own death awaits you full soon after that of
+Hector."
+</para>
+
+<para>
+Then said Achilles in his great grief, "I would die here and now,
+in that I could not save my comrade. He has fallen far from home,
+and in his hour of need my hand was not there to help him. What
+is there for me? Return to my own land I shall not, and I have
+brought no saving neither to Patroclus nor to my other comrades
+of whom so many have been slain by mighty Hector; I stay here by
+my ships a bootless burden upon the earth, I, who in fight have
+no peer among the Achaeans, though in council there are better
+than I. Therefore, perish strife both from among gods and men,
+and anger, wherein even a righteous man will harden his
+heart--which rises up in the soul of a man like smoke, and the
+taste thereof is sweeter than drops of honey. Even so has
+Agamemnon angered me. And yet--so be it, for it is over; I will
+force my soul into subjection as I needs must; I will go; I will
+pursue Hector who has slain him whom I loved so dearly, and will
+then abide my doom when it may please Jove and the other gods to
+send it. Even Hercules, the best beloved of Jove--even he could
+not escape the hand of death, but fate and Juno's fierce anger
+laid him low, as I too shall lie when I am dead if a like doom
+awaits me. Till then I will win fame, and will bid Trojan and
+Dardanian women wring tears from their tender cheeks with both
+their hands in the grievousness of their great sorrow; thus shall
+they know that he who has held aloof so long will hold aloof no
+longer. Hold me not back, therefore, in the love you bear me, for
+you shall not move me."
+</para>
+
+<para>
+Then silver-footed Thetis answered, "My son, what you have said
+is true. It is well to save your comrades from destruction, but
+your armour is in the hands of the Trojans; Hector bears it in
+triumph upon his own shoulders. Full well I know that his vaunt
+shall not be lasting, for his end is close at hand; go not,
+however, into the press of battle till you see me return hither;
+to-morrow at break of day I shall be here, and will bring you
+goodly armour from King Vulcan."
+</para>
+
+<para>
+On this she left her brave son, and as she turned away she said
+to the sea-nymphs her sisters, "Dive into the bosom of the sea
+and go to the house of the old sea-god my father. Tell him
+everything; as for me, I will go to the cunning workman Vulcan on
+high Olympus, and ask him to provide my son with a suit of
+splendid armour."
+</para>
+
+<para>
+When she had so said, they dived forthwith beneath the waves,
+while silver-footed Thetis went her way that she might bring the
+armour for her son.
+</para>
+
+<para>
+Thus, then, did her feet bear the goddess to Olympus, and
+meanwhile the Achaeans were flying with loud cries before
+murderous Hector till they reached the ships and the Hellespont,
+and they could not draw the body of Mars's servant Patroclus out
+of reach of the weapons that were showered upon him, for Hector
+son of Priam with his host and horsemen had again caught up to
+him like the flame of a fiery furnace; thrice did brave Hector
+seize him by the feet, striving with might and main to draw him
+away and calling loudly on the Trojans, and thrice did the two
+Ajaxes, clothed in valour as with a garment, beat him from off
+the body; but all undaunted he would now charge into the thick of
+the fight, and now again he would stand still and cry aloud, but
+he would give no ground. As upland shepherds that cannot chase
+some famished lion from a carcase, even so could not the two
+Ajaxes scare Hector son of Priam from the body of Patroclus.
+</para>
+
+<para>
+And now he would even have dragged it off and have won
+imperishable glory, had not Iris fleet as the wind, winged her
+way as messenger from Olympus to the son of Peleus and bidden him
+arm. She came secretly without the knowledge of Jove and of the
+other gods, for Juno sent her, and when she had got close to him
+she said, "Up, son of Peleus, mightiest of all mankind; rescue
+Patroclus about whom this fearful fight is now raging by the
+ships. Men are killing one another, the Danaans in defence of the
+dead body, while the Trojans are trying to hale it away, and take
+it to windy Ilius: Hector is the most furious of them all; he is
+for cutting the head from the body and fixing it on the stakes of
+the wall. Up, then, and bide here no longer; shrink from the
+thought that Patroclus may become meat for the dogs of Troy.
+Shame on you, should his body suffer any kind of outrage."
+</para>
+
+<para>
+And Achilles said, "Iris, which of the gods was it that sent you
+to me?"
+</para>
+
+<para>
+Iris answered, "It was Juno the royal spouse of Jove, but the son
+of Saturn does not know of my coming, nor yet does any other of
+the immortals who dwell on the snowy summits of Olympus."
+</para>
+
+<para>
+Then fleet Achilles answered her saying, "How can I go up into
+the battle? They have my armour. My mother forbade me to arm till
+I should see her come, for she promised to bring me goodly armour
+from Vulcan; I know no man whose arms I can put on, save only the
+shield of Ajax son of Telamon, and he surely must be fighting in
+the front rank and wielding his spear about the body of dead
+Patroclus."
+</para>
+
+<para>
+Iris said, "We know that your armour has been taken, but go as
+you are; go to the deep trench and show yourself before the
+Trojans, that they may fear you and cease fighting. Thus will the
+fainting sons of the Achaeans gain some brief breathing-time,
+which in battle may hardly be."
+</para>
+
+<para>
+Iris left him when she had so spoken. But Achilles dear to Jove
+arose, and Minerva flung her tasselled aegis round his strong
+shoulders; she crowned his head with a halo of golden cloud from
+which she kindled a glow of gleaming fire. As the smoke that goes
+up into heaven from some city that is being beleaguered on an
+island far out at sea--all day long do men sally from the city
+and fight their hardest, and at the going down of the sun the
+line of beacon-fires blazes forth, flaring high for those that
+dwell near them to behold, if so be that they may come with their
+ships and succour them--even so did the light flare from the head
+of Achilles, as he stood by the trench, going beyond the wall--
+but he aid not join the Achaeans for he heeded the charge which
+his mother laid upon him.
+</para>
+
+<para>
+There did he stand and shout aloud. Minerva also raised her voice
+from afar, and spread terror unspeakable among the Trojans.
+Ringing as the note of a trumpet that sounds alarm then the foe
+is at the gates of a city, even so brazen was the voice of the
+son of Aeacus, and when the Trojans heard its clarion tones they
+were dismayed; the horses turned back with their chariots for
+they boded mischief, and their drivers were awe-struck by the
+steady flame which the grey-eyed goddess had kindled above the
+head of the great son of Peleus.
+</para>
+
+<para>
+Thrice did Achilles raise his loud cry as he stood by the trench,
+and thrice were the Trojans and their brave allies thrown into
+confusion; whereon twelve of their noblest champions fell beneath
+the wheels of their chariots and perished by their own spears.
+The Achaeans to their great joy then drew Patroclus out of reach
+of the weapons, and laid him on a litter: his comrades stood
+mourning round him, and among them fleet Achilles who wept
+bitterly as he saw his true comrade lying dead upon his bier. He
+had sent him out with horses and chariots into battle, but his
+return he was not to welcome.
+</para>
+
+<para>
+Then Juno sent the busy sun, loth though he was, into the waters
+of Oceanus; so he set, and the Achaeans had rest from the tug and
+turmoil of war.
+</para>
+
+<para>
+Now the Trojans when they had come out of the fight, unyoked
+their horses and gathered in assembly before preparing their
+supper. They kept their feet, nor would any dare to sit down, for
+fear had fallen upon them all because Achilles had shown himself
+after having held aloof so long from battle. Polydamas son of
+Panthous was first to speak, a man of judgement, who alone among
+them could look both before and after. He was comrade to Hector,
+and they had been born upon the same night; with all sincerity
+and goodwill, therefore, he addressed them thus:--
+</para>
+
+<para>
+"Look to it well, my friends; I would urge you to go back now to
+your city and not wait here by the ships till morning, for we are
+far from our walls. So long as this man was at enmity with
+Agamemnon the Achaeans were easier to deal with, and I would have
+gladly camped by the ships in the hope of taking them; but now I
+go in great fear of the fleet son of Peleus; he is so daring that
+he will never bide here on the plain whereon the Trojans and
+Achaeans fight with equal valour, but he will try to storm our
+city and carry off our women. Do then as I say, and let us
+retreat. For this is what will happen. The darkness of night will
+for a time stay the son of Peleus, but if he find us here in the
+morning when he sallies forth in full armour, we shall have
+knowledge of him in good earnest. Glad indeed will he be who can
+escape and get back to Ilius, and many a Trojan will become meat
+for dogs and vultures may I never live to hear it. If we do as I
+say, little though we may like it, we shall have strength in
+counsel during the night, and the great gates with the doors that
+close them will protect the city. At dawn we can arm and take our
+stand on the walls; he will then rue it if he sallies from the
+ships to fight us. He will go back when he has given his horses
+their fill of being driven all whithers under our walls, and will
+be in no mind to try and force his way into the city. Neither
+will he ever sack it, dogs shall devour him ere he do so."
+</para>
+
+<para>
+Hector looked fiercely at him and answered, "Polydamas, your
+words are not to my liking in that you bid us go back and be pent
+within the city. Have you not had enough of being cooped up
+behind walls? In the old-days the city of Priam was famous the
+whole world over for its wealth of gold and bronze, but our
+treasures are wasted out of our houses, and much goods have been
+sold away to Phrygia and fair Meonia, for the hand of Jove has
+been laid heavily upon us. Now, therefore, that the son of
+scheming Saturn has vouchsafed me to win glory here and to hem
+the Achaeans in at their ships, prate no more in this fool's wise
+among the people. You will have no man with you; it shall not be;
+do all of you as I now say;--take your suppers in your companies
+throughout the host, and keep your watches and be wakeful every
+man of you. If any Trojan is uneasy about his possessions, let
+him gather them and give them out among the people. Better let
+these, rather than the Achaeans, have them. At daybreak we will
+arm and fight about the ships; granted that Achilles has again
+come forward to defend them, let it be as he will, but it shall
+go hard with him. I shall not shun him, but will fight him, to
+fall or conquer. The god of war deals out like measure to all,
+and the slayer may yet be slain."
+</para>
+
+<para>
+Thus spoke Hector; and the Trojans, fools that they were, shouted
+in applause, for Pallas Minerva had robbed them of their
+understanding. They gave ear to Hector with his evil counsel, but
+the wise words of Polydamas no man would heed. They took their
+supper throughout the host, and meanwhile through the whole night
+the Achaeans mourned Patroclus, and the son of Peleus led them in
+their lament. He laid his murderous hands upon the breast of his
+comrade, groaning again and again as a bearded lion when a man
+who was chasing deer has robbed him of his young in some dense
+forest; when the lion comes back he is furious, and searches
+dingle and dell to track the hunter if he can find him, for he is
+mad with rage--even so with many a sigh did Achilles speak among
+the Myrmidons saying, "Alas! vain were the words with which I
+cheered the hero Menoetius in his own house; I said that I would
+bring his brave son back again to Opoeis after he had sacked
+Ilius and taken his share of the spoils--but Jove does not give
+all men their heart's desire. The same soil shall be reddened
+here at Troy by the blood of us both, for I too shall never be
+welcomed home by the old knight Peleus, nor by my mother Thetis,
+but even in this place shall the earth cover me. Nevertheless, O
+Patroclus, now that I am left behind you, I will not bury you,
+till I have brought hither the head and armour of mighty Hector
+who has slain you. Twelve noble sons of Trojans will I behead
+before your bier to avenge you; till I have done so you shall lie
+as you are by the ships, and fair women of Troy and Dardanus,
+whom we have taken with spear and strength of arm when we sacked
+men's goodly cities, shall weep over you both night and day."
+</para>
+
+<para>
+Then Achilles told his men to set a large tripod upon the fire
+that they might wash the clotted gore from off Patroclus. Thereon
+they set a tripod full of bath water on to a clear fire: they
+threw sticks on to it to make it blaze, and the water became hot
+as the flame played about the belly of the tripod. When the water
+in the cauldron was boiling they washed the body, anointed it
+with oil, and closed its wounds with ointment that had been kept
+nine years. Then they laid it on a bier and covered it with a
+linen cloth from head to foot, and over this they laid a fair
+white robe. Thus all night long did the Myrmidons gather round
+Achilles to mourn Patroclus.
+</para>
+
+<para>
+Then Jove said to Juno his sister-wife, "So, Queen Juno, you have
+gained your end, and have roused fleet Achilles. One would think
+that the Achaeans were of your own flesh and blood."
+</para>
+
+<para>
+And Juno answered, "Dread son of Saturn, why should you say this
+thing? May not a man though he be only mortal and knows less than
+we do, do what he can for another person? And shall not I--
+foremost of all goddesses both by descent and as wife to you who
+reign in heaven--devise evil for the Trojans if I am angry with
+them?"
+</para>
+
+<para>
+Thus did they converse. Meanwhile Thetis came to the house of
+Vulcan, imperishable, star-bespangled, fairest of the abodes in
+heaven, a house of bronze wrought by the lame god's own hands.
+She found him busy with his bellows, sweating and hard at work,
+for he was making twenty tripods that were to stand by the wall
+of his house, and he set wheels of gold under them all that they
+might go of their own selves to the assemblies of the gods, and
+come back again--marvels indeed to see. They were finished all
+but the ears of cunning workmanship which yet remained to be
+fixed to them: these he was now fixing, and he was hammering at
+the rivets. While he was thus at work silver-footed Thetis came
+to the house. Charis, of graceful head-dress, wife to the
+far-famed lame god, came towards her as soon as she saw her, and
+took her hand in her own, saying, "Why have you come to our
+house, Thetis, honoured and ever welcome--for you do not visit us
+often? Come inside and let me set refreshment before you."
+</para>
+
+<para>
+The goddess led the way as she spoke, and bade Thetis sit on a
+richly decorated seat inlaid with silver; there was a footstool
+also under her feet. Then she called Vulcan and said, "Vulcan,
+come here, Thetis wants you"; and the far-famed lame god
+answered, "Then it is indeed an august and honoured goddess who
+has come here; she it was that took care of me when I was
+suffering from the heavy fall which I had through my cruel
+mother's anger--for she would have got rid of me because I was
+lame. It would have gone hardly with me had not Eurynome,
+daughter of the ever-encircling waters of Oceanus, and Thetis,
+taken me to their bosom. Nine years did I stay with them, and
+many beautiful works in bronze, brooches, spiral armlets, cups,
+and chains, did I make for them in their cave, with the roaring
+waters of Oceanus foaming as they rushed ever past it; and no one
+knew, neither of gods nor men, save only Thetis and Eurynome who
+took care of me. If, then, Thetis has come to my house I must
+make her due requital for having saved me; entertain her,
+therefore, with all hospitality, while I put by my bellows and
+all my tools."
+</para>
+
+<para>
+On this the mighty monster hobbled off from his anvil, his thin
+legs plying lustily under him. He set the bellows away from the
+fire, and gathered his tools into a silver chest. Then he took a
+sponge and washed his face and hands, his shaggy chest and brawny
+neck; he donned his shirt, grasped his strong staff, and limped
+towards the door. There were golden handmaids also who worked for
+him, and were like real young women, with sense and reason, voice
+also and strength, and all the learning of the immortals; these
+busied themselves as the king bade them, while he drew near to
+Thetis, seated her upon a goodly seat, and took her hand in his
+own, saying, "Why have you come to our house, Thetis honoured and
+ever welcome--for you do not visit us often? Say what you want,
+and I will do it for you at once if I can, and if it can be done
+at all."
+</para>
+
+<para>
+Thetis wept and answered, "Vulcan, is there another goddess in
+Olympus whom the son of Saturn has been pleased to try with so
+much affliction as he has me? Me alone of the marine goddesses
+did he make subject to a mortal husband, Peleus son of Aeacus,
+and sorely against my will did I submit to the embraces of one
+who was but mortal, and who now stays at home worn out with age.
+Neither is this all. Heaven vouchsafed me a son, hero among
+heroes, and he shot up as a sapling. I tended him as a plant in a
+goodly garden and sent him with his ships to Ilius to fight the
+Trojans, but never shall I welcome him back to the house of
+Peleus. So long as he lives to look upon the light of the sun, he
+is in heaviness, and though I go to him I cannot help him; King
+Agamemnon has made him give up the maiden whom the sons of the
+Achaeans had awarded him, and he wastes with sorrow for her sake.
+Then the Trojans hemmed the Achaeans in at their ships' sterns
+and would not let them come forth; the elders, therefore, of the
+Argives besought Achilles and offered him great treasure, whereon
+he refused to bring deliverance to them himself, but put his own
+armour on Patroclus and sent him into the fight with much people
+after him. All day long they fought by the Scaean gates and would
+have taken the city there and then, had not Apollo vouchsafed
+glory to Hector and slain the valiant son of Menoetius after he
+had done the Trojans much evil. Therefore I am suppliant at your
+knees if haply you may be pleased to provide my son, whose end is
+near at hand, with helmet and shield, with goodly greaves fitted
+with ancle-clasps, and with a breastplate, for he lost his own
+when his true comrade fell at the hands of the Trojans, and he
+now lies stretched on earth in the bitterness of his soul."
+</para>
+
+<para>
+And Vulcan answered, "Take heart, and be no more disquieted about
+this matter; would that I could hide him from death's sight when
+his hour is come, so surely as I can find him armour that shall
+amaze the eyes of all who behold it."
+</para>
+
+<para>
+When he had so said he left her and went to his bellows, turning
+them towards the fire and bidding them do their office. Twenty
+bellows blew upon the melting-pots, and they blew blasts of every
+kind, some fierce to help him when he had need of them, and
+others less strong as Vulcan willed it in the course of his work.
+He threw tough copper into the fire, and tin, with silver and
+gold; he set his great anvil on its block, and with one hand
+grasped his mighty hammer while he took the tongs in the other.
+</para>
+
+<para>
+First he shaped the shield so great and strong, adorning it all
+over and binding it round with a gleaming circuit in three
+layers; and the baldric was made of silver. He made the shield in
+five thicknesses, and with many a wonder did his cunning hand
+enrich it.
+</para>
+
+<para>
+He wrought the earth, the heavens, and the sea; the moon also at
+her full and the untiring sun, with all the signs that glorify
+the face of heaven--the Pleiads, the Hyads, huge Orion, and the
+Bear, which men also call the Wain and which turns round ever in
+one place, facing. Orion, and alone never dips into the stream of
+Oceanus.
+</para>
+
+<para>
+He wrought also two cities, fair to see and busy with the hum of
+men. In the one were weddings and wedding-feasts, and they were
+going about the city with brides whom they were escorting by
+torchlight from their chambers. Loud rose the cry of Hymen, and
+the youths danced to the music of flute and lyre, while the women
+stood each at her house door to see them.
+</para>
+
+<para>
+Meanwhile the people were gathered in assembly, for there was a
+quarrel, and two men were wrangling about the blood-money for a
+man who had been killed, the one saying before the people that he
+had paid damages in full, and the other that he had not been
+paid. Each was trying to make his own case good, and the people
+took sides, each man backing the side that he had taken; but the
+heralds kept them back, and the elders sate on their seats of
+stone in a solemn circle, holding the staves which the heralds
+had put into their hands. Then they rose and each in his turn
+gave judgement, and there were two talents laid down, to be given
+to him whose judgement should be deemed the fairest.
+</para>
+
+<para>
+About the other city there lay encamped two hosts in gleaming
+armour, and they were divided whether to sack it, or to spare it
+and accept the half of what it contained. But the men of the city
+would not yet consent, and armed themselves for a surprise; their
+wives and little children kept guard upon the walls, and with
+them were the men who were past fighting through age; but the
+others sallied forth with Mars and Pallas Minerva at their head--
+both of them wrought in gold and clad in golden raiment, great
+and fair with their armour as befitting gods, while they that
+followed were smaller. When they reached the place where they
+would lay their ambush, it was on a riverbed to which live stock
+of all kinds would come from far and near to water; here, then,
+they lay concealed, clad in full armour. Some way off them there
+were two scouts who were on the look-out for the coming of sheep
+or cattle, which presently came, followed by two shepherds who
+were playing on their pipes, and had not so much as a thought of
+danger. When those who were in ambush saw this, they cut off the
+flocks and herds and killed the shepherds. Meanwhile the
+besiegers, when they heard much noise among the cattle as they
+sat in council, sprang to their horses, and made with all speed
+towards them; when they reached them they set battle in array by
+the banks of the river, and the hosts aimed their bronze-shod
+spears at one another. With them were Strife and Riot, and fell
+Fate who was dragging three men after her, one with a fresh
+wound, and the other unwounded, while the third was dead, and she
+was dragging him along by his heel: and her robe was bedrabbled
+in men's blood. They went in and out with one another and fought
+as though they were living people haling away one another's dead.
+</para>
+
+<para>
+He wrought also a fair fallow field, large and thrice ploughed
+already. Many men were working at the plough within it, turning
+their oxen to and fro, furrow after furrow. Each time that they
+turned on reaching the headland a man would come up to them and
+give them a cup of wine, and they would go back to their furrows
+looking forward to the time when they should again reach the
+headland. The part that they had ploughed was dark behind them,
+so that the field, though it was of gold, still looked as if it
+were being ploughed--very curious to behold.
+</para>
+
+<para>
+He wrought also a field of harvest corn, and the reapers were
+reaping with sharp sickles in their hands. Swathe after swathe
+fell to the ground in a straight line behind them, and the
+binders bound them in bands of twisted straw. There were three
+binders, and behind them there were boys who gathered the cut
+corn in armfuls and kept on bringing them to be bound: among them
+all the owner of the land stood by in silence and was glad. The
+servants were getting a meal ready under an oak, for they had
+sacrificed a great ox, and were busy cutting him up, while the
+women were making a porridge of much white barley for the
+labourers' dinner.
+</para>
+
+<para>
+He wrought also a vineyard, golden and fair to see, and the vines
+were loaded with grapes. The bunches overhead were black, but the
+vines were trained on poles of silver. He ran a ditch of dark
+metal all round it, and fenced it with a fence of tin; there was
+only one path to it, and by this the vintagers went when they
+would gather the vintage. Youths and maidens all blithe and full
+of glee, carried the luscious fruit in plaited baskets; and with
+them there went a boy who made sweet music with his lyre, and
+sang the Linos-song with his clear boyish voice.
+</para>
+
+<para>
+He wrought also a herd of horned cattle. He made the cows of gold
+and tin, and they lowed as they came full speed out of the yards
+to go and feed among the waving reeds that grow by the banks of
+the river. Along with the cattle there went four shepherds, all
+of them in gold, and their nine fleet dogs went with them. Two
+terrible lions had fastened on a bellowing bull that was with the
+foremost cows, and bellow as he might they haled him, while the
+dogs and men gave chase: the lions tore through the bull's thick
+hide and were gorging on his blood and bowels, but the herdsmen
+were afraid to do anything, and only hounded on their dogs; the
+dogs dared not fasten on the lions but stood by barking and
+keeping out of harm's way.
+</para>
+
+<para>
+The god wrought also a pasture in a fair mountain dell, and a
+large flock of sheep, with a homestead and huts, and sheltered
+sheepfolds.
+</para>
+
+<para>
+Furthermore he wrought a green, like that which Daedalus once
+made in Cnossus for lovely Ariadne. Hereon there danced youths
+and maidens whom all would woo, with their hands on one another's
+wrists. The maidens wore robes of light linen, and the youths
+well woven shirts that were slightly oiled. The girls were
+crowned with garlands, while the young men had daggers of gold
+that hung by silver baldrics; sometimes they would dance deftly
+in a ring with merry twinkling feet, as it were a potter sitting
+at his work and making trial of his wheel to see whether it will
+run, and sometimes they would go all in line with one another,
+and much people was gathered joyously about the green. There was
+a bard also to sing to them and play his lyre, while two tumblers
+went about performing in the midst of them when the man struck up
+with his tune.
+</para>
+
+<para>
+All round the outermost rim of the shield he set the mighty
+stream of the river Oceanus.
+</para>
+
+<para>
+Then when he had fashioned the shield so great and strong, he
+made a breastplate also that shone brighter than fire. He made a
+helmet, close fitting to the brow, and richly worked, with a
+golden plume overhanging it; and he made greaves also of beaten
+tin.
+</para>
+
+<para>
+Lastly, when the famed lame god had made all the armour, he took
+it and set it before the mother of Achilles; whereon she darted
+like a falcon from the snowy summits of Olympus and bore away the
+gleaming armour from the house of Vulcan.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK XIX</title>
+
+<para>
+NOW when Dawn in robe of saffron was hasting from the streams of
+Oceanus, to bring light to mortals and immortals, Thetis reached
+the ships with the armour that the god had given her. She found
+her son fallen about the body of Patroclus and weeping bitterly.
+Many also of his followers were weeping round him, but when the
+goddess came among them she clasped his hand in her own, saying,
+"My son, grieve as we may we must let this man lie, for it is by
+heaven's will that he has fallen; now, therefore, accept from
+Vulcan this rich and goodly armour, which no man has ever yet
+borne upon his shoulders."
+</para>
+
+<para>
+As she spoke she set the armour before Achilles, and it rang out
+bravely as she did so. The Myrmidons were struck with awe, and
+none dared look full at it, for they were afraid; but Achilles
+was roused to still greater fury, and his eyes gleamed with a
+fierce light, for he was glad when he handled the splendid
+present which the god had made him. Then, as soon as he had
+satisfied himself with looking at it, he said to his mother,
+"Mother, the god has given me armour, meet handiwork for an
+immortal and such as no-one living could have fashioned; I will
+now arm, but I much fear that flies will settle upon the son of
+Menoetius and breed worms about his wounds, so that his body, now
+he is dead, will be disfigured and the flesh will rot."
+</para>
+
+<para>
+Silver-footed Thetis answered, "My son, be not disquieted about
+this matter. I will find means to protect him from the swarms of
+noisome flies that prey on the bodies of men who have been killed
+in battle. He may lie for a whole year, and his flesh shall still
+be as sound as ever, or even sounder. Call, therefore, the
+Achaean heroes in assembly; unsay your anger against Agamemnon;
+arm at once, and fight with might and main."
+</para>
+
+<para>
+As she spoke she put strength and courage into his heart, and she
+then dropped ambrosia and red nectar into the wounds of
+Patroclus, that his body might suffer no change.
+</para>
+
+<para>
+Then Achilles went out upon the seashore, and with a loud cry
+called on the Achaean heroes. On this even those who as yet had
+stayed always at the ships, the pilots and helmsmen, and even the
+stewards who were about the ships and served out rations, all
+came to the place of assembly because Achilles had shown himself
+after having held aloof so long from fighting. Two sons of Mars,
+Ulysses and the son of Tydeus, came limping, for their wounds
+still pained them; nevertheless they came, and took their seats
+in the front row of the assembly. Last of all came Agamemnon,
+king of men, he too wounded, for Coon son of Antenor had struck
+him with a spear in battle.
+</para>
+
+<para>
+When the Achaeans were got together Achilles rose and said, "Son
+of Atreus, surely it would have been better alike for both you
+and me, when we two were in such high anger about Briseis, surely
+it would have been better, had Diana's arrow slain her at the
+ships on the day when I took her after having sacked Lyrnessus.
+For so, many an Achaean the less would have bitten dust before
+the foe in the days of my anger. It has been well for Hector and
+the Trojans, but the Achaeans will long indeed remember our
+quarrel. Now, however, let it be, for it is over. If we have been
+angry, necessity has schooled our anger. I put it from me: I dare
+not nurse it for ever; therefore, bid the Achaeans arm forthwith
+that I may go out against the Trojans, and learn whether they
+will be in a mind to sleep by the ships or no. Glad, I ween, will
+he be to rest his knees who may fly my spear when I wield it."
+</para>
+
+<para>
+Thus did he speak, and the Achaeans rejoiced in that he had put
+away his anger.
+</para>
+
+<para>
+Then Agamemnon spoke, rising in his place, and not going into the
+middle of the assembly. "Danaan heroes," said he, "servants of
+Mars, it is well to listen when a man stands up to speak, and it
+is not seemly to interrupt him, or it will go hard even with a
+practised speaker. Who can either hear or speak in an uproar?
+Even the finest orator will be disconcerted by it. I will expound
+to the son of Peleus, and do you other Achaeans heed me and mark
+me well. Often have the Achaeans spoken to me of this matter and
+upbraided me, but it was not I that did it: Jove, and Fate, and
+Erinys that walks in darkness struck me mad when we were
+assembled on the day that I took from Achilles the meed that had
+been awarded to him. What could I do? All things are in the hand
+of heaven, and Folly, eldest of Jove's daughters, shuts men's
+eyes to their destruction. She walks delicately, not on the solid
+earth, but hovers over the heads of men to make them stumble or
+to ensnare them.
+</para>
+
+<para>
+"Time was when she fooled Jove himself, who they say is greatest
+whether of gods or men; for Juno, woman though she was, beguiled
+him on the day when Alcmena was to bring forth mighty Hercules in
+the fair city of Thebes. He told it out among the gods saying,
+'Hear me, all gods and goddesses, that I may speak even as I am
+minded; this day shall an Ilithuia, helper of women who are in
+labour, bring a man child into the world who shall be lord over
+all that dwell about him who are of my blood and lineage.' Then
+said Juno all crafty and full of guile, 'You will play false, and
+will not hold to your word. Swear me, O Olympian, swear me a
+great oath, that he who shall this day fall between the feet of a
+woman, shall be lord over all that dwell about him who are of
+your blood and lineage.'
+</para>
+
+<para>
+"Thus she spoke, and Jove suspected her not, but swore the great
+oath, to his much ruing thereafter. For Juno darted down from the
+high summit of Olympus, and went in haste to Achaean Argos where
+she knew that the noble wife of Sthenelus son of Perseus then
+was. She being with child and in her seventh month, Juno brought
+the child to birth though there was a month still wanting, but
+she stayed the offspring of Alcmena, and kept back the Ilithuiae.
+Then she went to tell Jove the son of Saturn, and said, 'Father
+Jove, lord of the lightning--I have a word for your ear. There is
+a fine child born this day, Eurystheus, son to Sthenelus the son
+of Perseus; he is of your lineage; it is well, therefore, that he
+should reign over the Argives.'
+</para>
+
+<para>
+"On this Jove was stung to the very quick, and in his rage he
+caught Folly by the hair, and swore a great oath that never
+should she again invade starry heaven and Olympus, for she was
+the bane of all. Then he whirled her round with a twist of his
+hand, and flung her down from heaven so that she fell on to the
+fields of mortal men; and he was ever angry with her when he saw
+his son groaning under the cruel labours that Eurystheus laid
+upon him. Even so did I grieve when mighty Hector was killing the
+Argives at their ships, and all the time I kept thinking of Folly
+who had so baned me. I was blind, and Jove robbed me of my
+reason; I will now make atonement, and will add much treasure by
+way of amends. Go, therefore, into battle, you and your people
+with you. I will give you all that Ulysses offered you yesterday
+in your tents: or if it so please you, wait, though you would
+fain fight at once, and my squires shall bring the gifts from my
+ship, that you may see whether what I give you is enough."
+</para>
+
+<para>
+And Achilles answered, "Son of Atreus, king of men Agamemnon, you
+can give such gifts as you think proper, or you can withhold
+them: it is in your own hands. Let us now set battle in array; it
+is not well to tarry talking about trifles, for there is a deed
+which is as yet to do. Achilles shall again be seen fighting
+among the foremost, and laying low the ranks of the Trojans: bear
+this in mind each one of you when he is fighting."
+</para>
+
+<para>
+Then Ulysses said, "Achilles, godlike and brave, send not the
+Achaeans thus against Ilius to fight the Trojans fasting, for the
+battle will be no brief one, when it is once begun, and heaven
+has filled both sides with fury; bid them first take food both
+bread and wine by the ships, for in this there is strength and
+stay. No man can do battle the livelong day to the going down of
+the sun if he is without food; however much he may want to fight
+his strength will fail him before he knows it; hunger and thirst
+will find him out, and his limbs will grow weary under him. But a
+man can fight all day if he is full fed with meat and wine; his
+heart beats high, and his strength will stay till he has routed
+all his foes; therefore, send the people away and bid them
+prepare their meal; King Agamemnon will bring out the gifts in
+presence of the assembly, that all may see them and you may be
+satisfied. Moreover let him swear an oath before the Argives that
+he has never gone up into the couch of Briseis, nor been with her
+after the manner of men and women; and do you, too, show yourself
+of a gracious mind; let Agamemnon entertain you in his tents with
+a feast of reconciliation, that so you may have had your dues in
+full. As for you, son of Atreus, treat people more righteously in
+future; it is no disgrace even to a king that he should make
+amends if he was wrong in the first instance."
+</para>
+
+<para>
+And King Agamemnon answered, "Son of Laertes, your words please
+me well, for throughout you have spoken wisely. I will swear as
+you would have me do; I do so of my own free will, neither shall
+I take the name of heaven in vain. Let, then, Achilles wait,
+though he would fain fight at once, and do you others wait also,
+till the gifts come from my tent and we ratify the oath with
+sacrifice. Thus, then, do I charge you: take some noble young
+Achaeans with you, and bring from my tents the gifts that I
+promised yesterday to Achilles, and bring the women also;
+furthermore let Talthybius find me a boar from those that are
+with the host, and make it ready for sacrifice to Jove and to the
+sun."
+</para>
+
+<para>
+Then said Achilles, "Son of Atreus, king of men Agamemnon, see to
+these matters at some other season, when there is breathing time
+and when I am calmer. Would you have men eat while the bodies of
+those whom Hector son of Priam slew are still lying mangled upon
+the plain? Let the sons of the Achaeans, say I, fight fasting and
+without food, till we have avenged them; afterwards at the going
+down of the sun let them eat their fill. As for me, Patroclus is
+lying dead in my tent, all hacked and hewn, with his feet to the
+door, and his comrades are mourning round him. Therefore I can
+take thought of nothing save only slaughter and blood and the
+rattle in the throat of the dying."
+</para>
+
+<para>
+Ulysses answered, "Achilles, son of Peleus, mightiest of all the
+Achaeans, in battle you are better than I, and that more than a
+little, but in counsel I am much before you, for I am older and
+of greater knowledge. Therefore be patient under my words.
+Fighting is a thing of which men soon surfeit, and when Jove, who
+is war's steward, weighs the upshot, it may well prove that the
+straw which our sickles have reaped is far heavier than the
+grain. It may not be that the Achaeans should mourn the dead with
+their bellies; day by day men fall thick and threefold
+continually; when should we have respite from our sorrow? Let us
+mourn our dead for a day and bury them out of sight and mind, but
+let those of us who are left eat and drink that we may arm and
+fight our foes more fiercely. In that hour let no man hold back,
+waiting for a second summons; such summons shall bode ill for him
+who is found lagging behind at our ships; let us rather sally as
+one man and loose the fury of war upon the Trojans."
+</para>
+
+<para>
+When he had thus spoken he took with him the sons of Nestor, with
+Meges son of Phyleus, Thoas, Meriones, Lycomedes son of Creontes,
+and Melanippus, and went to the tent of Agamemnon son of Atreus.
+The word was not sooner said than the deed was done: they
+brought out the seven tripods which Agamemnon had promised, with
+the twenty metal cauldrons and the twelve horses; they also
+brought the women skilled in useful arts, seven in number, with
+Briseis, which made eight. Ulysses weighed out the ten talents of
+gold and then led the way back, while the young Achaeans brought
+the rest of the gifts, and laid them in the middle of the
+assembly.
+</para>
+
+<para>
+Agamemnon then rose, and Talthybius whose voice was like that of
+a god came to him with the boar. The son of Atreus drew the knife
+which he wore by the scabbard of his mighty sword, and began by
+cutting off some bristles from the boar, lifting up his hands in
+prayer as he did so. The other Achaeans sat where they were all
+silent and orderly to hear the king, and Agamemnon looked into
+the vault of heaven and prayed saying, "I call Jove the first and
+mightiest of all gods to witness, I call also Earth and Sun and
+the Erinyes who dwell below and take vengeance on him who shall
+swear falsely, that I have laid no hand upon the girl Briseis,
+neither to take her to my bed nor otherwise, but that she has
+remained in my tents inviolate. If I swear falsely may heaven
+visit me with all the penalties which it metes out to those who
+perjure themselves."
+</para>
+
+<para>
+He cut the boar's throat as he spoke, whereon Talthybius whirled
+it round his head, and flung it into the wide sea to feed the
+fishes. Then Achilles also rose and said to the Argives, "Father
+Jove, of a truth you blind men's eyes and bane them. The son of
+Atreus had not else stirred me to so fierce an anger, nor so
+stubbornly taken Briseis from me against my will. Surely Jove
+must have counselled the destruction of many an Argive. Go, now,
+and take your food that we may begin fighting."
+</para>
+
+<para>
+On this he broke up the assembly, and every man went back to his
+own ship. The Myrmidons attended to the presents and took them
+away to the ship of Achilles. They placed them in his tents,
+while the stable-men drove the horses in among the others.
+</para>
+
+<para>
+Briseis, fair as Venus, when she saw the mangled body of
+Patroclus, flung herself upon it and cried aloud, tearing her
+breast, her neck, and her lovely face with both her hands.
+Beautiful as a goddess she wept and said, "Patroclus, dearest
+friend, when I went hence I left you living; I return, O prince,
+to find you dead; thus do fresh sorrows multiply upon me one
+after the other. I saw him to whom my father and mother married
+me, cut down before our city, and my three own dear brothers
+perished with him on the self-same day; but you, Patroclus, even
+when Achilles slew my husband and sacked the city of noble Mynes,
+told me that I was not to weep, for you said you would make
+Achilles marry me, and take me back with him to Phthia, we should
+have a wedding feast among the Myrmidons. You were always kind to
+me and I shall never cease to grieve for you."
+</para>
+
+<para>
+She wept as she spoke, and the women joined in her lament-making
+as though their tears were for Patroclus, but in truth each was
+weeping for her own sorrows. The elders of the Achaeans gathered
+round Achilles and prayed him to take food, but he groaned and
+would not do so. "I pray you," said he, "if any comrade will hear
+me, bid me neither eat nor drink, for I am in great heaviness,
+and will stay fasting even to the going down of the sun."
+</para>
+
+<para>
+On this he sent the other princes away, save only the two sons of
+Atreus and Ulysses, Nestor, Idomeneus, and the knight Phoenix,
+who stayed behind and tried to comfort him in the bitterness of
+his sorrow: but he would not be comforted till he should have
+flung himself into the jaws of battle, and he fetched sigh on
+sigh, thinking ever of Patroclus. Then he said--
+</para>
+
+<para>
+"Hapless and dearest comrade, you it was who would get a good
+dinner ready for me at once and without delay when the Achaeans
+were hasting to fight the Trojans; now, therefore, though I have
+meat and drink in my tents, yet will I fast for sorrow. Grief
+greater than this I could not know, not even though I were to
+hear of the death of my father, who is now in Phthia weeping for
+the loss of me his son, who am here fighting the Trojans in a
+strange land for the accursed sake of Helen, nor yet though I
+should hear that my son is no more--he who is being brought up in
+Scyros--if indeed Neoptolemus is still living. Till now I made
+sure that I alone was to fall here at Troy away from Argos, while
+you were to return to Phthia, bring back my son with you in your
+own ship, and show him all my property, my bondsmen, and the
+greatness of my house--for Peleus must surely be either dead, or
+what little life remains to him is oppressed alike with the
+infirmities of age and ever present fear lest he should hear the
+sad tidings of my death."
+</para>
+
+<para>
+He wept as he spoke, and the elders sighed in concert as each
+thought on what he had left at home behind him. The son of Saturn
+looked down with pity upon them, and said presently to Minerva,
+"My child, you have quite deserted your hero; is he then gone so
+clean out of your recollection? There he sits by the ships all
+desolate for the loss of his dear comrade, and though the others
+are gone to their dinner he will neither eat nor drink. Go then
+and drop nectar and ambrosia into his breast, that he may know no
+hunger."
+</para>
+
+<para>
+With these words he urged Minerva, who was already of the same
+mind. She darted down from heaven into the air like some falcon
+sailing on his broad wings and screaming. Meanwhile the Achaeans
+were arming throughout the host, and when Minerva had dropped
+nectar and ambrosia into Achilles so that no cruel hunger should
+cause his limbs to fail him, she went back to the house of her
+mighty father. Thick as the chill snow-flakes shed from the hand
+of Jove and borne on the keen blasts of the north wind, even so
+thick did the gleaming helmets, the bossed shields, the strongly
+plated breastplates, and the ashen spears stream from the ships.
+The sheen pierced the sky, the whole land was radiant with their
+flashing armour, and the sound of the tramp of their treading
+rose from under their feet. In the midst of them all Achilles put
+on his armour; he gnashed his teeth, his eyes gleamed like fire,
+for his grief was greater than he could bear. Thus, then, full of
+fury against the Trojans, did he don the gift of the god, the
+armour that Vulcan had made him.
+</para>
+
+<para>
+First he put on the goodly greaves fitted with ancle-clasps, and
+next he did on the breastplate about his chest. He slung the
+silver-studded sword of bronze about his shoulders, and then took
+up the shield so great and strong that shone afar with a
+splendour as of the moon. As the light seen by sailors from out
+at sea, when men have lit a fire in their homestead high up among
+the mountains, but the sailors are carried out to sea by wind and
+storm far from the haven where they would be--even so did the
+gleam of Achilles' wondrous shield strike up into the heavens. He
+lifted the redoubtable helmet, and set it upon his head, from
+whence it shone like a star, and the golden plumes which Vulcan
+had set thick about the ridge of the helmet, waved all around it.
+Then Achilles made trial of himself in his armour to see whether
+it fitted him, so that his limbs could play freely under it, and
+it seemed to buoy him up as though it had been wings.
+</para>
+
+<para>
+He also drew his father's spear out of the spear-stand, a spear
+so great and heavy and strong that none of the Achaeans save only
+Achilles had strength to wield it; this was the spear of Pelian
+ash from the topmost ridges of Mt. Pelion, which Chiron had once
+given to Peleus, fraught with the death of heroes. Automedon and
+Alcimus busied themselves with the harnessing of his horses; they
+made the bands fast about them, and put the bit in their mouths,
+drawing the reins back towards the chariot. Automedon, whip in
+hand, sprang up behind the horses, and after him Achilles mounted
+in full armour, resplendent as the sun-god Hyperion. Then with a
+loud voice he chided with his father's horses saying, "Xanthus
+and Balius, famed offspring of Podarge--this time when we have
+done fighting be sure and bring your driver safely back to the
+host of the Achaeans, and do not leave him dead on the plain as
+you did Patroclus."
+</para>
+
+<para>
+Then fleet Xanthus answered under the yoke--for white-armed Juno
+had endowed him with human speech--and he bowed his head till his
+mane touched the ground as it hung down from under the yoke-band.
+"Dread Achilles," said he, "we will indeed save you now, but the
+day of your death is near, and the blame will not be ours, for it
+will be heaven and stern fate that will destroy you. Neither was
+it through any sloth or slackness on our part that the Trojans
+stripped Patroclus of his armour; it was the mighty god whom
+lovely Leto bore that slew him as he fought among the foremost,
+and vouchsafed a triumph to Hector. We two can fly as swiftly as
+Zephyrus who they say is fleetest of all winds; nevertheless it
+is your doom to fall by the hand of a man and of a god."
+</para>
+
+<para>
+When he had thus said the Erinyes stayed his speech, and Achilles
+answered him in great sadness, saying, "Why, O Xanthus, do you
+thus foretell my death? You need not do so, for I well know that
+I am to fall here, far from my dear father and mother; none the
+more, however, shall I stay my hand till I have given the Trojans
+their fill of fighting."
+</para>
+
+<para>
+So saying, with a loud cry he drove his horses to the front.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK XX</title>
+
+<para>
+THUS, then, did the Achaeans arm by their ships round you, O son
+of Peleus, who were hungering for battle; while the Trojans over
+against them armed upon the rise of the plain.
+</para>
+
+<para>
+Meanwhile Jove from the top of many-delled Olympus, bade Themis
+gather the gods in council, whereon she went about and called
+them to the house of Jove. There was not a river absent except
+Oceanus, nor a single one of the nymphs that haunt fair groves,
+or springs of rivers and meadows of green grass. When they
+reached the house of cloud-compelling Jove, they took their seats
+in the arcades of polished marble which Vulcan with his
+consummate skill had made for father Jove.
+</para>
+
+<para>
+In such wise, therefore, did they gather in the house of Jove.
+Neptune also, lord of the earthquake, obeyed the call of the
+goddess, and came up out of the sea to join them. There, sitting
+in the midst of them, he asked what Jove's purpose might be.
+"Why," said he, "wielder of the lightning, have you called the
+gods in council? Are you considering some matter that concerns
+the Trojans and Achaeans--for the blaze of battle is on the point
+of being kindled between them?"
+</para>
+
+<para>
+And Jove answered, "You know my purpose, shaker of earth, and
+wherefore I have called you hither. I take thought for them even
+in their destruction. For my own part I shall stay here seated on
+Mt. Olympus and look on in peace, but do you others go about
+among Trojans and Achaeans, and help either side as you may be
+severally disposed. If Achilles fights the Trojans without
+hindrance they will make no stand against him; they have ever
+trembled at the sight of him, and now that he is roused to such
+fury about his comrade, he will override fate itself and storm
+their city."
+</para>
+
+<para>
+Thus spoke Jove and gave the word for war, whereon the gods took
+their several sides and went into battle. Juno, Pallas Minerva,
+earth-encircling Neptune, Mercury bringer of good luck and
+excellent in all cunning--all these joined the host that came
+from the ships; with them also came Vulcan in all his glory,
+limping, but yet with his thin legs plying lustily under him.
+Mars of gleaming helmet joined the Trojans, and with him Apollo
+of locks unshorn, and the archer goddess Diana, Leto, Xanthus,
+and laughter-loving Venus.
+</para>
+
+<para>
+So long as the gods held themselves aloof from mortal warriors
+the Achaeans were triumphant, for Achilles who had long refused
+to fight was now with them. There was not a Trojan but his limbs
+failed him for fear as he beheld the fleet son of Peleus all
+glorious in his armour, and looking like Mars himself. When,
+however, the Olympians came to take their part among men,
+forthwith uprose strong Strife, rouser of hosts, and Minerva
+raised her loud voice, now standing by the deep trench that ran
+outside the wall, and now shouting with all her might upon the
+shore of the sounding sea. Mars also bellowed out upon the other
+side, dark as some black thunder-cloud, and called on the Trojans
+at the top of his voice, now from the acropolis, and now speeding
+up the side of the river Simois till he came to the hill
+Callicolone.
+</para>
+
+<para>
+Thus did the gods spur on both hosts to fight, and rouse fierce
+contention also among themselves. The sire of gods and men
+thundered from heaven above, while from beneath Neptune shook the
+vast earth, and bade the high hills tremble. The spurs and crests
+of many-fountained Ida quaked, as also the city of the Trojans
+and the ships of the Achaeans. Hades, king of the realms below,
+was struck with fear; he sprang panic-stricken from his throne
+and cried aloud in terror lest Neptune, lord of the earthquake,
+should crack the ground over his head, and lay bare his mouldy
+mansions to the sight of mortals and immortals--mansions so
+ghastly grim that even the gods shudder to think of them. Such
+was the uproar as the gods came together in battle. Apollo with
+his arrows took his stand to face King Neptune, while Minerva
+took hers against the god of war; the archer-goddess Diana with
+her golden arrows, sister of far-darting Apollo, stood to face
+Juno; Mercury the lusty bringer of good luck faced Leto, while
+the mighty eddying river whom men can Scamander, but gods
+Xanthus, matched himself against Vulcan.
+</para>
+
+<para>
+The gods, then, were thus ranged against one another. But the
+heart of Achilles was set on meeting Hector son of Priam, for it
+was with his blood that he longed above all things else to glut
+the stubborn lord of battle. Meanwhile Apollo set Aeneas on to
+attack the son of Peleus, and put courage into his heart,
+speaking with the voice of Lycaon son of Priam. In his likeness
+therefore, he said to Aeneas, "Aeneas, counsellor of the Trojans,
+where are now the brave words with which you vaunted over your
+wine before the Trojan princes, saying that you would fight
+Achilles son of Peleus in single combat?"
+</para>
+
+<para>
+And Aeneas answered, "Why do you thus bid me fight the proud son
+of Peleus, when I am in no mind to do so? Were I to face him now,
+it would not be for the first time. His spear has already put me
+to Right from Ida, when he attacked our cattle and sacked
+Lyrnessus and Pedasus; Jove indeed saved me in that he vouchsafed
+me strength to fly, else had the fallen by the hands of Achilles
+and Minerva, who went before him to protect him and urged him to
+fall upon the Lelegae and Trojans. No man may fight Achilles, for
+one of the gods is always with him as his guardian angel, and
+even were it not so, his weapon flies ever straight, and fails
+not to pierce the flesh of him who is against him; if heaven
+would let me fight him on even terms he should not soon overcome
+me, though he boasts that he is made of bronze."
+</para>
+
+<para>
+Then said King Apollo, son to Jove, "Nay, hero, pray to the
+ever-living gods, for men say that you were born of Jove's
+daughter Venus, whereas Achilles is son to a goddess of inferior
+rank. Venus is child to Jove, while Thetis is but daughter to the
+old man of the sea. Bring, therefore, your spear to bear upon
+him, and let him not scare you with his taunts and menaces."
+</para>
+
+<para>
+As he spoke he put courage into the heart of the shepherd of his
+people, and he strode in full armour among the ranks of the
+foremost fighters. Nor did the son of Anchises escape the notice
+of white-armed Juno, as he went forth into the throng to meet
+Achilles. She called the gods about her, and said, "Look to it,
+you two, Neptune and Minerva, and consider how this shall be;
+Phoebus Apollo has been sending Aeneas clad in full armour to
+fight Achilles. Shall we turn him back at once, or shall one of
+us stand by Achilles and endow him with strength so that his
+heart fail not, and he may learn that the chiefs of the immortals
+are on his side, while the others who have all along been
+defending the Trojans are but vain helpers? Let us all come down
+from Olympus and join in the fight, that this day he may take no
+hurt at the hands of the Trojans. Hereafter let him suffer
+whatever fate may have spun out for him when he was begotten and
+his mother bore him. If Achilles be not thus assured by the voice
+of a god, he may come to fear presently when one of us meets him
+in battle, for the gods are terrible if they are seen face to
+face."
+</para>
+
+<para>
+Neptune lord of the earthquake answered her saying, "Juno,
+restrain your fury; it is not well; I am not in favour of forcing
+the other gods to fight us, for the advantage is too greatly on
+our own side; let us take our places on some hill out of the
+beaten track, and let mortals fight it out among themselves. If
+Mars or Phoebus Apollo begin fighting, or keep Achilles in check
+so that he cannot fight, we too, will at once raise the cry of
+battle, and in that case they will soon leave the field and go
+back vanquished to Olympus among the other gods."
+</para>
+
+<para>
+With these words the dark-haired god led the way to the high
+earth-barrow of Hercules, built round solid masonry, and made by
+the Trojans and Pallas Minerva for him fly to when the
+sea-monster was chasing him from the shore on to the plain. Here
+Neptune and those that were with him took their seats, wrapped in
+a thick cloud of darkness; but the other gods seated themselves
+on the brow of Callicolone round you, O Phoebus, and Mars the
+waster of cities.
+</para>
+
+<para>
+Thus did the gods sit apart and form their plans, but neither
+side was willing to begin battle with the other, and Jove from
+his seat on high was in command over them all. Meanwhile the
+whole plain was alive with men and horses, and blazing with the
+gleam of armour. The earth rang again under the tramp of their
+feet as they rushed towards each other, and two champions, by far
+the foremost of them all, met between the hosts to fight--to wit,
+Aeneas son of Anchises, and noble Achilles.
+</para>
+
+<para>
+Aeneas was first to stride forward in attack, his doughty helmet
+tossing defiance as he came on. He held his strong shield before
+his breast, and brandished his bronze spear. The son of Peleus
+from the other side sprang forth to meet him, like some fierce
+lion that the whole country-side has met to hunt and kill--at
+first he bodes no ill, but when some daring youth has struck him
+with a spear, he crouches openmouthed, his jaws foam, he roars
+with fury, he lashes his tail from side to side about his ribs
+and loins, and glares as he springs straight before him, to find
+out whether he is to slay, or be slain among the foremost of his
+foes--even with such fury did Achilles burn to spring upon
+Aeneas.
+</para>
+
+<para>
+When they were now close up with one another Achilles was first
+to speak. "Aeneas," said he, "why do you stand thus out before
+the host to fight me? Is it that you hope to reign over the
+Trojans in the seat of Priam? Nay, though you kill me Priam will
+not hand his kingdom over to you. He is a man of sound judgement,
+and he has sons of his own. Or have the Trojans been allotting
+you a demesne of passing richness, fair with orchard lawns and
+corn lands, if you should slay me? This you shall hardly do. I
+have discomfited you once already. Have you forgotten how when
+you were alone I chased you from your herds helter-skelter down
+the slopes of Ida? You did not turn round to look behind you; you
+took refuge in Lyrnessus, but I attacked the city, and with the
+help of Minerva and father Jove I sacked it and carried its women
+into captivity, though Jove and the other gods rescued you. You
+think they will protect you now, but they will not do so;
+therefore I say go back into the host, and do not face me, or you
+will rue it. Even a fool may be wise after the event."
+</para>
+
+<para>
+Then Aeneas answered, "Son of Peleus, think not that your words
+can scare me as though I were a child. I too, if I will, can brag
+and talk unseemly. We know one another's race and parentage as
+matters of common fame, though neither have you ever seen my
+parents nor I yours. Men say that you are son to noble Peleus,
+and that your mother is Thetis, fair-haired daughter of the sea.
+I have noble Anchises for my father, and Venus for my mother; the
+parents of one or other of us shall this day mourn a son, for it
+will be more than silly talk that shall part us when the fight is
+over. Learn, then, my lineage if you will--and it is known to
+many.
+</para>
+
+<para>
+"In the beginning Dardanus was the son of Jove, and founded
+Dardania, for Ilius was not yet stablished on the plain for men
+to dwell in, and her people still abode on the spurs of
+many-fountained Ida. Dardanus had a son, king Erichthonius, who
+was wealthiest of all men living; he had three thousand mares
+that fed by the water-meadows, they and their foals with them.
+Boreas was enamoured of them as they were feeding, and covered
+them in the semblance of a dark-maned stallion. Twelve filly
+foals did they conceive and bear him, and these, as they sped
+over the rich plain, would go bounding on over the ripe ears of
+corn and not break them; or again when they would disport
+themselves on the broad back of Ocean they could gallop on the
+crest of a breaker. Erichthonius begat Tros, king of the Trojans,
+and Tros had three noble sons, Ilus, Assaracus, and Ganymede who
+was comeliest of mortal men; wherefore the gods carried him off
+to be Jove's cupbearer, for his beauty's sake, that he might
+dwell among the immortals. Ilus begat Laomedon, and Laomedon
+begat Tithonus, Priam, Lampus, Clytius, and Hiketaon of the stock
+of Mars. But Assaracus was father to Capys, and Capys to
+Anchises, who was my father, while Hector is son to Priam.
+</para>
+
+<para>
+"Such do I declare my blood and lineage, but as for valour, Jove
+gives it or takes it as he will, for he is lord of all. And now
+let there be no more of this prating in mid-battle as though we
+were children. We could fling taunts without end at one another;
+a hundred-oared galley would not hold them. The tongue can run
+all whithers and talk all wise; it can go here and there, and as
+a man says, so shall he be gainsaid. What is the use of our
+bandying hard like women who when they fall foul of one another
+go out and wrangle in the streets, one half true and the other
+lies, as rage inspires them? No words of yours shall turn me now
+that I am fain to fight--therefore let us make trial of one
+another with our spears."
+</para>
+
+<para>
+As he spoke he drove his spear at the great and terrible shield
+of Achilles, which rang out as the point struck it. The son of
+Peleus held the shield before him with his strong hand, and he
+was afraid, for he deemed that Aeneas's spear would go through it
+quite easily, not reflecting that the god's glorious gifts were
+little likely to yield before the blows of mortal men; and indeed
+Aeneas's spear did not pierce the shield, for the layer of gold,
+gift of the god, stayed the point. It went through two layers,
+but the god had made the shield in five, two of bronze, the two
+innermost ones of tin, and one of gold; it was in this that the
+spear was stayed.
+</para>
+
+<para>
+Achilles in his turn threw, and struck the round shield of Aeneas
+at the very edge, where the bronze was thinnest; the spear of
+Pelian ash went clean through, and the shield rang under the
+blow; Aeneas was afraid, and crouched backwards, holding the
+shield away from him; the spear, however, flew over his back, and
+stuck quivering in the ground, after having gone through both
+circles of the sheltering shield. Aeneas though he had avoided
+the spear, stood still, blinded with fear and grief because the
+weapon had gone so near him; then Achilles sprang furiously upon
+him, with a cry as of death and with his keen blade drawn, and
+Aeneas seized a great stone, so huge that two men, as men now
+are, would be unable to lift it, but Aeneas wielded it quite
+easily.
+</para>
+
+<para>
+Aeneas would then have struck Achilles as he was springing
+towards him, either on the helmet, or on the shield that covered
+him, and Achilles would have closed with him and despatched him
+with his sword, had not Neptune lord of the earthquake been quick
+to mark, and said forthwith to the immortals, "Alas, I am sorry
+for great Aeneas, who will now go down to the house of Hades,
+vanquished by the son of Peleus. Fool that he was to give ear to
+the counsel of Apollo. Apollo will never save him from
+destruction. Why should this man suffer when he is guiltless, to
+no purpose, and in another's quarrel? Has he not at all times
+offered acceptable sacrifice to the gods that dwell in heaven?
+Let us then snatch him from death's jaws, lest the son of Saturn
+be angry should Achilles slay him. It is fated, moreover, that he
+should escape, and that the race of Dardanus, whom Jove loved
+above all the sons born to him of mortal women, shall not perish
+utterly without seed or sign. For now indeed has Jove hated the
+blood of Priam, while Aeneas shall reign over the Trojans, he and
+his children's children that shall be born hereafter."
+</para>
+
+<para>
+Then answered Juno, "Earth-shaker, look to this matter yourself,
+and consider concerning Aeneas, whether you will save him, or
+suffer him, brave though he be, to fall by the hand of Achilles
+son of Peleus. For of a truth we two, I and Pallas Minerva, have
+sworn full many a time before all the immortals, that never would
+we shield Trojans from destruction, not even when all Troy is
+burning in the flames that the Achaeans shall kindle."
+</para>
+
+<para>
+When earth-encircling Neptune heard this he went into the battle
+amid the clash of spears, and came to the place where Achilles
+and Aeneas were. Forthwith he shed a darkness before the eyes of
+the son of Peleus, drew the bronze-headed ashen spear from the
+shield of Aeneas, and laid it at the feet of Achilles. Then he
+lifted Aeneas on high from off the earth and hurried him away.
+Over the heads of many a band of warriors both horse and foot did
+he soar as the god's hand sped him, till he came to the very
+fringe of the battle where the Cauconians were arming themselves
+for fight. Neptune, shaker of the earth, then came near to him
+and said, "Aeneas, what god has egged you on to this folly in
+fighting the son of Peleus, who is both a mightier man of valour
+and more beloved of heaven than you are? Give way before him
+whensoever you meet him, lest you go down to the house of Hades
+even though fate would have it otherwise. When Achilles is dead
+you may then fight among the foremost undaunted, for none other
+of the Achaeans shall slay you."
+</para>
+
+<para>
+The god left him when he had given him these instructions, and at
+once removed the darkness from before the eyes of Achilles, who
+opened them wide indeed and said in great anger, "Alas! what
+marvel am I now beholding? Here is my spear upon the ground, but
+I see not him whom I meant to kill when I hurled it. Of a truth
+Aeneas also must be under heaven's protection, although I had
+thought his boasting was idle. Let him go hang; he will be in no
+mood to fight me further, seeing how narrowly he has missed being
+killed. I will now give my orders to the Danaans and attack some
+other of the Trojans."
+</para>
+
+<para>
+He sprang forward along the line and cheered his men on as he did
+so. "Let not the Trojans," he cried, "keep you at arm's length,
+Achaeans, but go for them and fight them man for man. However
+valiant I may be, I cannot give chase to so many and fight all of
+them. Even Mars, who is an immortal, or Minerva, would shrink
+from flinging himself into the jaws of such a fight and laying
+about him; nevertheless, so far as in me lies I will show no
+slackness of hand or foot nor want of endurance, not even for a
+moment; I will utterly break their ranks, and woe to the Trojan
+who shall venture within reach of my spear."
+</para>
+
+<para>
+Thus did he exhort them. Meanwhile Hector called upon the Trojans
+and declared that he would fight Achilles. "Be not afraid, proud
+Trojans," said he, "to face the son of Peleus; I could fight gods
+myself if the battle were one of words only, but they would be
+more than a match for me, if we had to use our spears. Even so
+the deed of Achilles will fall somewhat short of his word; he
+will do in part, and the other part he will clip short. I will go
+up against him though his hands be as fire--though his hands be
+fire and his strength iron."
+</para>
+
+<para>
+Thus urged the Trojans lifted up their spears against the
+Achaeans, and raised the cry of battle as they flung themselves
+into the midst of their ranks. But Phoebus Apollo came up to
+Hector and said, "Hector, on no account must you challenge
+Achilles to single combat; keep a lookout for him while you are
+under cover of the others and away from the thick of the fight,
+otherwise he will either hit you with a spear or cut you down at
+close quarters."
+</para>
+
+<para>
+Thus he spoke, and Hector drew back within the crowd, for he was
+afraid when he heard what the god had said to him. Achilles then
+sprang upon the Trojans with a terrible cry, clothed in valour as
+with a garment. First he killed Iphition son of Otrynteus, a
+leader of much people whom a naiad nymph had borne to Otrynteus
+waster of cities, in the land of Hyde under the snowy heights of
+Mt. Tmolus. Achilles struck him full on the head as he was coming
+on towards him, and split it clean in two; whereon he fell
+heavily to the ground and Achilles vaunted over him saying, "You
+be low, son of Otrynteus, mighty hero; your death is here, but
+your lineage is on the Gygaean lake where your father's estate
+lies, by Hyllus, rich in fish, and the eddying waters of Hermus."
+</para>
+
+<para>
+Thus did he vaunt, but darkness closed the eyes of the other.
+The chariots of the Achaeans cut him up as their wheels passed
+over him in the front of the battle, and after him Achilles
+killed Demoleon, a valiant man of war and son to Antenor. He
+struck him on the temple through his bronze-cheeked helmet. The
+helmet did not stay the spear, but it went right on, crushing the
+bone so that the brain inside was shed in all directions, and his
+lust of fighting was ended. Then he struck Hippodamas in the
+midriff as he was springing down from his chariot in front of
+him, and trying to escape. He breathed his last, bellowing like a
+bull bellows when young men are dragging him to offer him in
+sacrifice to the King of Helice, and the heart of the
+earth-shaker is glad; even so did he bellow as he lay dying.
+Achilles then went in pursuit of Polydorus son of Priam, whom his
+father had always forbidden to fight because he was the youngest
+of his sons, the one he loved best, and the fastest runner. He,
+in his folly and showing off the fleetness of his feet, was
+rushing about among front ranks until he lost his life, for
+Achilles struck him in the middle of the back as he was darting
+past him: he struck him just at the golden fastenings of his belt
+and where the two pieces of the double breastplate overlapped.
+The point of the spear pierced him through and came out by the
+navel, whereon he fell groaning on to his knees and a cloud of
+darkness overshadowed him as he sank holding his entrails in his
+hands.
+</para>
+
+<para>
+When Hector saw his brother Polydorus with his entrails in his
+hands and sinking down upon the ground, a mist came over his
+eyes, and he could not bear to keep longer at a distance; he
+therefore poised his spear and darted towards Achilles like a
+flame of fire. When Achilles saw him he bounded forward and
+vaunted saying, "This is he that has wounded my heart most deeply
+and has slain my beloved comrade. Not for long shall we two quail
+before one another on the highways of war."
+</para>
+
+<para>
+He looked fiercely on Hector and said, "Draw near, that you may
+meet your doom the sooner." Hector feared him not and answered,
+"Son of Peleus, think not that your words can scare me as though
+I were a child; I too if I will can brag and talk unseemly; I
+know that you are a mighty warrior, mightier by far than I,
+nevertheless the issue lies in the lap of heaven whether I, worse
+man though I be, may not slay you with my spear, for this too has
+been found keen ere now."
+</para>
+
+<para>
+He hurled his spear as he spoke, but Minerva breathed upon it,
+and though she breathed but very lightly she turned it back from
+going towards Achilles, so that it returned to Hector and lay at
+his feet in front of him. Achilles then sprang furiously on him
+with a loud cry, bent on killing him, but Apollo caught him up
+easily as a god can, and hid him in a thick darkness. Thrice did
+Achilles spring towards him spear in hand, and thrice did he
+waste his blow upon the air. When he rushed forward for the
+fourth time as though he were a god, he shouted aloud saying,
+"Hound, this time too you have escaped death--but of a truth it
+came exceedingly near you. Phoebus Apollo, to whom it seems you
+pray before you go into battle, has again saved you; but if I too
+have any friend among the gods I will surely make an end of you
+when I come across you at some other time. Now, however, I will
+pursue and overtake other Trojans."
+</para>
+
+<para>
+On this he struck Dryops with his spear, about the middle of his
+neck, and he fell headlong at his feet. There he let him lie and
+stayed Demouchus son of Philetor, a man both brave and of great
+stature, by hitting him on the knee with a spear; then he smote
+him with his sword and killed him. After this he sprang on
+Laogonus and Dardanus, sons of Bias, and threw them from their
+chariot, the one with a blow from a thrown spear, while the other
+he cut down in hand-to-hand fight. There was also Tros the son of
+Alastor--he came up to Achilles and clasped his knees in the hope
+that he would spare him and not kill him but let him go, because
+they were both of the same age. Fool, he might have known that he
+should not prevail with him, for the man was in no mood for pity
+or forbearance but was in grim earnest. Therefore when Tros laid
+hold of his knees and sought a hearing for his prayers, Achilles
+drove his sword into his liver, and the liver came rolling out,
+while his bosom was all covered with the black blood that welled
+from the wound. Thus did death close his eyes as he lay lifeless.
+</para>
+
+<para>
+Achilles then went up to Mulius and struck him on the ear with a
+spear, and the bronze spear-head came right out at the other ear.
+He also struck Echeclus son of Agenor on the head with his sword,
+which became warm with the blood, while death and stern fate
+closed the eyes of Echeclus. Next in order the bronze point of
+his spear wounded Deucalion in the fore-arm where the sinews of
+the elbow are united, whereon he waited Achilles' onset with his
+arm hanging down and death staring him in the face. Achilles cut
+his head off with a blow from his sword and flung it helmet and
+all away from him, and the marrow came oozing out of his backbone
+as he lay. He then went in pursuit of Rhigmus, noble son of
+Peires, who had come from fertile Thrace, and struck him through
+the middle with a spear which fixed itself in his belly, so that
+he fell headlong from his chariot. He also speared Areithous
+squire to Rhigmus in the back as he was turning his horses in
+flight, and thrust him from his chariot, while the horses were
+struck with panic.
+</para>
+
+<para>
+As a fire raging in some mountain glen after long drought--and
+the dense forest is in a blaze, while the wind carries great
+tongues of fire in every direction--even so furiously did
+Achilles rage, wielding his spear as though he were a god, and
+giving chase to those whom he would slay, till the dark earth ran
+with blood. Or as one who yokes broad-browed oxen that they may
+tread barley in a threshing-floor--and it is soon bruised small
+under the feet of the lowing cattle--even so did the horses of
+Achilles trample on the shields and bodies of the slain. The axle
+underneath and the railing that ran round the car were
+bespattered with clots of blood thrown up by the horses' hoofs,
+and from the tyres of the wheels; but the son of Peleus pressed
+on to win still further glory, and his hands were bedrabbled with
+gore.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK XXI</title>
+
+<para>
+NOW when they came to the ford of the full-flowing river Xanthus,
+begotten of immortal Jove, Achilles cut their forces in two: one
+half he chased over the plain towards the city by the same way
+that the Achaeans had taken when flying panic-stricken on the
+preceding day with Hector in full triumph; this way did they fly
+pell-mell, and Juno sent down a thick mist in front of them to
+stay them. The other half were hemmed in by the deep
+silver-eddying stream, and fell into it with a great uproar. The
+waters resounded, and the banks rang again, as they swam hither
+and thither with loud cries amid the whirling eddies. As locusts
+flying to a river before the blast of a grass fire--the flame
+comes on and on till at last it overtakes them and they huddle
+into the water--even so was the eddying stream of Xanthus filled
+with the uproar of men and horses, all struggling in confusion
+before Achilles.
+</para>
+
+<para>
+Forthwith the hero left his spear upon the bank, leaning it
+against a tamarisk bush, and plunged into the river like a god,
+armed with his sword only. Fell was his purpose as he hewed the
+Trojans down on every side. Their dying groans rose hideous as
+the sword smote them, and the river ran red with blood. As when
+fish fly scared before a huge dolphin, and fill every nook and
+corner of some fair haven--for he is sure to eat all he can
+catch--even so did the Trojans cower under the banks of the
+mighty river, and when Achilles' arms grew weary with killing
+them, he drew twelve youths alive out of the water, to sacrifice
+in revenge for Patroclus son of Menoetius. He drew them out like
+dazed fawns, bound their hands behind them with the girdles of
+their own shirts, and gave them over to his men to take back to
+the ships. Then he sprang into the river, thirsting for still
+further blood.
+</para>
+
+<para>
+There he found Lycaon, son of Priam seed of Dardanus, as he was
+escaping out of the water; he it was whom he had once taken
+prisoner when he was in his father's vineyard, having set upon
+him by night, as he was cutting young shoots from a wild fig-tree
+to make the wicker sides of a chariot. Achilles then caught him
+to his sorrow unawares, and sent him by sea to Lemnos, where the
+son of Jason bought him. But a guest-friend, Eetion of Imbros,
+freed him with a great sum, and sent him to Arisbe, whence he had
+escaped and returned to his father's house. He had spent eleven
+days happily with his friends after he had come from Lemnos, but
+on the twelfth heaven again delivered him into the hands of
+Achilles, who was to send him to the house of Hades sorely
+against his will. He was unarmed when Achilles caught sight of
+him, and had neither helmet nor shield; nor yet had he any spear,
+for he had thrown all his armour from him on to the bank, and was
+sweating with his struggles to get out of the river, so that his
+strength was now failing him.
+</para>
+
+<para>
+Then Achilles said to himself in his surprise, "What marvel do I
+see here? If this man can come back alive after having been sold
+over into Lemnos, I shall have the Trojans also whom I have slain
+rising from the world below. Could not even the waters of the
+grey sea imprison him, as they do many another whether he will or
+no? This time let him taste my spear, that I may know for certain
+whether mother earth who can keep even a strong man down, will be
+able to hold him, or whether thence too he will return."
+</para>
+
+<para>
+Thus did he pause and ponder. But Lycaon came up to him dazed and
+trying hard to embrace his knees, for he would fain live, not
+die. Achilles thrust at him with his spear, meaning to kill him,
+but Lycaon ran crouching up to him and caught his knees, whereby
+the spear passed over his back, and stuck in the ground,
+hungering though it was for blood. With one hand he caught
+Achilles' knees as he besought him, and with the other he
+clutched the spear and would not let it go. Then he said,
+"Achilles, have mercy upon me and spare me, for I am your
+suppliant. It was in your tents that I first broke bread on the
+day when you took me prisoner in the vineyard; after which you
+sold me away to Lemnos far from my father and my friends, and I
+brought you the price of a hundred oxen. I have paid three times
+as much to gain my freedom; it is but twelve days that I have
+come to Ilius after much suffering, and now cruel fate has again
+thrown me into your hands. Surely father Jove must hate me, that
+he has given me over to you a second time. Short of life indeed
+did my mother Laothoe bear me, daughter of aged Altes--of Altes
+who reigns over the warlike Lelegae and holds steep Pedasus on
+the river Satnioeis. Priam married his daughter along with many
+other women and two sons were born of her, both of whom you will
+have slain. Your spear slew noble Polydorus as he was fighting in
+the front ranks, and now evil will here befall me, for I fear
+that I shall not escape you since heaven has delivered me over to
+you. Furthermore I say, and lay my saying to your heart, spare
+me, for I am not of the same womb as Hector who slew your brave
+and noble comrade."
+</para>
+
+<para>
+With such words did the princely son of Priam beseech Achilles;
+but Achilles answered him sternly. "Idiot," said he, "talk not to
+me of ransom. Until Patroclus fell I preferred to give the
+Trojans quarter, and sold beyond the sea many of those whom I had
+taken alive; but now not a man shall live of those whom heaven
+delivers into my hands before the city of Ilius--and of all
+Trojans it shall fare hardest with the sons of Priam. Therefore,
+my friend, you too shall die. Why should you whine in this way?
+Patroclus fell, and he was a better man than you are. I too--see
+you not how I am great and goodly? I am son to a noble father,
+and have a goddess for my mother, but the hands of doom and death
+overshadow me all as surely. The day will come, either at dawn or
+dark, or at the noontide, when one shall take my life also in
+battle, either with his spear, or with an arrow sped from his
+bow."
+</para>
+
+<para>
+Thus did he speak, and Lycaon's heart sank within him. He loosed
+his hold of the spear, and held out both hands before him; but
+Achilles drew his keen blade, and struck him by the collar-bone
+on his neck; he plunged his two-edged sword into him to the very
+hilt, whereon he lay at full length on the ground, with the dark
+blood welling from him till the earth was soaked. Then Achilles
+caught him by the foot and flung him into the river to go down
+stream, vaunting over him the while, and saying, "Lie there among
+the fishes, who will lick the blood from your wound and gloat
+over it; your mother shall not lay you on any bier to mourn you,
+but the eddies of Scamander shall bear you into the broad bosom
+of the sea. There shall the fishes feed on the fat of Lycaon as
+they dart under the dark ripple of the waters--so perish all of
+you till we reach the citadel of strong Ilius--you in flight, and
+I following after to destroy you. The river with its broad silver
+stream shall serve you in no stead, for all the bulls you offered
+him and all the horses that you flung living into his waters.
+None the less miserably shall you perish till there is not a man
+of you but has paid in full for the death of Patroclus and the
+havoc you wrought among the Achaeans whom you have slain while I
+held aloof from battle."
+</para>
+
+<para>
+So spoke Achilles, but the river grew more and more angry, and
+pondered within himself how he should stay the hand of Achilles
+and save the Trojans from disaster. Meanwhile the son of Peleus,
+spear in hand, sprang upon Asteropaeus son of Pelegon to kill
+him. He was son to the broad river Axius and Periboea eldest
+daughter of Acessamenus; for the river had lain with her.
+Asteropaeus stood up out of the water to face him with a spear in
+either hand, and Xanthus filled him with courage, being angry for
+the death of the youths whom Achilles was slaying ruthlessly
+within his waters. When they were close up with one another
+Achilles was first to speak. "Who and whence are you," said he,
+"who dare to face me? Woe to the parents whose son stands up
+against me." And the son of Pelegon answered, "Great son of
+Peleus, why should you ask my lineage. I am from the fertile land
+of far Paeonia, captain of the Paeonians, and it is now eleven
+days that I am at Ilius. I am of the blood of the river Axius--of
+Axius that is the fairest of all rivers that run. He begot the
+famed warrior Pelegon, whose son men call me. Let us now fight,
+Achilles."
+</para>
+
+<para>
+Thus did he defy him, and Achilles raised his spear of Pelian
+ash. Asteropaeus failed with both his spears, for he could use
+both hands alike; with the one spear he struck Achilles' shield,
+but did not pierce it, for the layer of gold, gift of the god,
+stayed the point; with the other spear he grazed the elbow of
+Achilles' right arm drawing dark blood, but the spear itself went
+by him and fixed itself in the ground, foiled of its bloody
+banquet. Then Achilles, fain to kill him, hurled his spear at
+Asteropaeus, but failed to hit him and struck the steep bank of
+the river, driving the spear half its length into the earth. The
+son of Peleus then drew his sword and sprang furiously upon him.
+Asteropaeus vainly tried to draw Achilles' spear out of the bank
+by main force; thrice did he tug at it, trying with all his might
+to draw it out, and thrice he had to leave off trying; the fourth
+time he tried to bend and break it, but ere he could do so
+Achilles smote him with his sword and killed him. He struck him
+in the belly near the navel, so that all his bowels came gushing
+out on to the ground, and the darkness of death came over him as
+he lay gasping. Then Achilles set his foot on his chest and
+spoiled him of his armour, vaunting over him and saying, "Lie
+there--begotten of a river though you be, it is hard for you to
+strive with the offspring of Saturn's son. You declare yourself
+sprung from the blood of a broad river, but I am of the seed of
+mighty Jove. My father is Peleus, son of Aeacus ruler over the
+many Myrmidons, and Aeacus was the son of Jove. Therefore as Jove
+is mightier than any river that flows into the sea, so are his
+children stronger than those of any river whatsoever. Moreover
+you have a great river hard by if he can be of any use to you,
+but there is no fighting against Jove the son of Saturn, with
+whom not even King Achelous can compare, nor the mighty stream of
+deep-flowing Oceanus, from whom all rivers and seas with all
+springs and deep wells proceed; even Oceanus fears the lightnings
+of great Jove, and his thunder that comes crashing out of
+heaven."
+</para>
+
+<para>
+With this he drew his bronze spear out of the bank, and now that
+he had killed Asteropaeus, he let him lie where he was on the
+sand, with the dark water flowing over him and the eels and
+fishes busy nibbling and gnawing the fat that was about his
+kidneys. Then he went in chase of the Paeonians, who were flying
+along the bank of the river in panic when they saw their leader
+slain by the hands of the son of Peleus. Therein he slew
+Thersilochus, Mydon, Astypylus, Mnesus, Thrasius, Oeneus, and
+Ophelestes, and he would have slain yet others, had not the river
+in anger taken human form, and spoken to him from out the deep
+waters saying, "Achilles, if you excel all in strength, so do you
+also in wickedness, for the gods are ever with you to protect
+you: if, then, the son of Saturn has vouchsafed it to you to
+destroy all the Trojans, at any rate drive them out of my stream,
+and do your grim work on land. My fair waters are now filled with
+corpses, nor can I find any channel by which I may pour myself
+into the sea for I am choked with dead, and yet you go on
+mercilessly slaying. I am in despair, therefore, O captain of
+your host, trouble me no further."
+</para>
+
+<para>
+Achilles answered, "So be it, Scamander, Jove-descended; but I
+will never cease dealing out death among the Trojans, till I have
+pent them up in their city, and made trial of Hector face to
+face, that I may learn whether he is to vanquish me, or I him."
+</para>
+
+<para>
+As he spoke he set upon the Trojans with a fury like that of the
+gods. But the river said to Apollo, "Surely, son of Jove, lord of
+the silver bow, you are not obeying the commands of Jove who
+charged you straitly that you should stand by the Trojans and
+defend them, till twilight fades, and darkness is over an the
+earth."
+</para>
+
+<para>
+Meanwhile Achilles sprang from the bank into mid-stream, whereon
+the river raised a high wave and attacked him. He swelled his
+stream into a torrent, and swept away the many dead whom Achilles
+had slain and left within his waters. These he cast out on to the
+land, bellowing like a bull the while, but the living he saved
+alive, hiding them in his mighty eddies. The great and terrible
+wave gathered about Achilles, falling upon him and beating on his
+shield, so that he could not keep his feet; he caught hold of a
+great elm-tree, but it came up by the roots, and tore away the
+bank, damming the stream with its thick branches and bridging it
+all across; whereby Achilles struggled out of the stream, and
+fled full speed over the plain, for he was afraid.
+</para>
+
+<para>
+But the mighty god ceased not in his pursuit, and sprang upon him
+with a dark-crested wave, to stay his hands and save the Trojans
+from destruction. The son of Peleus darted away a spear's throw
+from him; swift as the swoop of a black hunter-eagle which is the
+strongest and fleetest of all birds, even so did he spring
+forward, and the armour rang loudly about his breast. He fled on
+in front, but the river with a loud roar came tearing after. As
+one who would water his garden leads a stream from some fountain
+over his plants, and all his ground-spade in hand he clears away
+the dams to free the channels, and the little stones run rolling
+round and round with the water as it goes merrily down the bank
+faster than the man can follow--even so did the river keep
+catching up with Achilles albeit he was a fleet runner, for the
+gods are stronger than men. As often as he would strive to stand
+his ground, and see whether or no all the gods in heaven were in
+league against him, so often would the mighty wave come beating
+down upon his shoulders, and be would have to keep flying on and
+on in great dismay; for the angry flood was tiring him out as it
+flowed past him and ate the ground from under his feet.
+</para>
+
+<para>
+Then the son of Peleus lifted up his voice to heaven saying,
+"Father Jove, is there none of the gods who will take pity upon
+me, and save me from the river? I do not care what may happen to
+me afterwards. I blame none of the other dwellers on Olympus so
+severely as I do my dear mother, who has beguiled and tricked me.
+She told me I was to fall under the walls of Troy by the flying
+arrows of Apollo; would that Hector, the best man among the
+Trojans, might there slay me; then should I fall a hero by the
+hand of a hero; whereas now it seems that I shall come to a most
+pitiable end, trapped in this river as though I were some
+swineherd's boy, who gets carried down a torrent while trying to
+cross it during a storm."
+</para>
+
+<para>
+As soon as he had spoken thus, Neptune and Minerva came up to him
+in the likeness of two men, and took him by the hand to reassure
+him. Neptune spoke first. "Son of Peleus," said he, "be not so
+exceeding fearful; we are two gods, come with Jove's sanction to
+assist you, I, and Pallas Minerva. It is not your fate to perish
+in this river; he will abate presently as you will see; moreover
+we strongly advise you, if you will be guided by us, not to stay
+your hand from fighting till you have pent the Trojan host within
+the famed walls of Ilius--as many of them as may escape. Then
+kill Hector and go back to the ships, for we will vouchsafe you a
+triumph over him."
+</para>
+
+<para>
+When they had so said they went back to the other immortals, but
+Achilles strove onward over the plain, encouraged by the charge
+the gods had laid upon him. All was now covered with the flood of
+waters, and much goodly armour of the youths that had been slain
+was rifting about, as also many corpses, but he forced his way
+against the stream, speeding right onwards, nor could the broad
+waters stay him, for Minerva had endowed him with great strength.
+Nevertheless Scamander did not slacken in his pursuit, but was
+still more furious with the son of Peleus. He lifted his waters
+into a high crest and cried aloud to Simois saying, "Dear
+brother, let the two of us unite to save this man, or he will
+sack the mighty city of King Priam, and the Trojans will not hold
+out against him. Help me at once; fill your streams with water
+from their sources, rouse all your torrents to a fury; raise your
+wave on high, and let snags and stones come thundering down you
+that we may make an end of this savage creature who is now
+lording it as though he were a god. Nothing shall serve him
+longer, not strength nor comeliness, nor his fine armour, which
+forsooth shall soon be lying low in the deep waters covered over
+with mud. I will wrap him in sand, and pour tons of shingle round
+him, so that the Achaeans shall not know how to gather his bones
+for the silt in which I shall have hidden him, and when they
+celebrate his funeral they need build no barrow."
+</para>
+
+<para>
+On this he upraised his tumultuous flood high against Achilles,
+seething as it was with foam and blood and the bodies of the
+dead. The dark waters of the river stood upright and would have
+overwhelmed the son of Peleus, but Juno, trembling lest Achilles
+should be swept away in the mighty torrent, lifted her voice on
+high and called out to Vulcan her son. "Crook-foot," she cried,
+"my child, be up and doing, for I deem it is with you that
+Xanthus is fain to fight; help us at once, kindle a fierce fire;
+I will then bring up the west and the white south wind in a
+mighty hurricane from the sea, that shall bear the flames against
+the heads and armour of the Trojans and consume them, while you
+go along the banks of Xanthus burning his trees and wrapping him
+round with fire. Let him not turn you back neither by fair words
+nor foul, and slacken not till I shout and tell you. Then you may
+stay your flames."
+</para>
+
+<para>
+On this Vulcan kindled a fierce fire, which broke out first upon
+the plain and burned the many dead whom Achilles had killed and
+whose bodies were lying about in great numbers; by this means the
+plain was dried and the flood stayed. As the north wind, blowing
+on an orchard that has been sodden with autumn rain, soon dries
+it, and the heart of the owner is glad--even so the whole plain
+was dried and the dead bodies were consumed. Then he turned
+tongues of fire on to the river. He burned the elms the willows
+and the tamarisks, the lotus also, with the rushes and marshy
+herbage that grew abundantly by the banks of the river. The eels
+and fishes that go darting about everywhere in the water, these,
+too, were sorely harassed by the flames that cunning Vulcan had
+kindled, and the river himself was scalded, so that he spoke
+saying, "Vulcan, there is no god can hold his own against you. I
+cannot fight you when you flare out your flames in this way;
+strive with me no longer. Let Achilles drive the Trojans out of
+city immediately. What have I to do with quarrelling and helping
+people?"
+</para>
+
+<para>
+He was boiling as he spoke, and all his waters were seething. As
+a cauldron upon a large fire boils when it is melting the lard of
+some fatted hog, and the lard keeps bubbling up all over when the
+dry faggots blaze under it--even so were the goodly waters of
+Xanthus heated with the fire till they were boiling. He could
+flow no longer but stayed his stream, so afflicted was he by the
+blasts of fire which cunning Vulcan had raised. Then he prayed to
+Juno and besought her saying, "Juno, why should your son vex my
+stream with such especial fury? I am not so much to blame as all
+the others are who have been helping the Trojans. I will leave
+off, since you so desire it, and let son leave off also.
+Furthermore I swear never again will I do anything to save the
+Trojans from destruction, not even when all Troy is burning in
+the flames which the Achaeans will kindle."
+</para>
+
+<para>
+As soon as Juno heard this she said to her son Vulcan, "Son
+Vulcan, hold now your flames; we ought not to use such violence
+against a god for the sake of mortals."
+</para>
+
+<para>
+When she had thus spoken Vulcan quenched his flames, and the
+river went back once more into his own fair bed.
+</para>
+
+<para>
+Xanthus was now beaten, so these two left off fighting, for Juno
+stayed them though she was still angry; but a furious quarrel
+broke out among the other gods, for they were of divided
+counsels. They fell on one another with a mighty uproar--earth
+groaned, and the spacious firmament rang out as with a blare of
+trumpets. Jove heard as he was sitting on Olympus, and laughed
+for joy when he saw the gods coming to blows among themselves.
+They were not long about beginning, and Mars piercer of shields
+opened the battle. Sword in hand he sprang at once upon Minerva
+and reviled her. "Why, vixen," said he, "have you again set the
+gods by the ears in the pride and haughtiness of your heart? Have
+you forgotten how you set Diomed son of Tydeus on to wound me,
+and yourself took visible spear and drove it into me to the hurt
+of my fair body? You shall now suffer for what you then did to
+me."
+</para>
+
+<para>
+As he spoke he struck her on the terrible tasselled aegis--so
+terrible that not even can Jove's lightning pierce it. Here did
+murderous Mars strike her with his great spear. She drew back and
+with her strong hand seized a stone that was lying on the plain--
+great and rugged and black--which men of old had set for the
+boundary of a field. With this she struck Mars on the neck, and
+brought him down. Nine roods did he cover in his fall, and his
+hair was all soiled in the dust, while his armour rang rattling
+round him. But Minerva laughed and vaunted over him saying,
+"Idiot, have you not learned how far stronger I am than you, but
+you must still match yourself against me? Thus do your mother's
+curses now roost upon you, for she is angry and would do you
+mischief because you have deserted the Achaeans and are helping
+the Trojans."
+</para>
+
+<para>
+She then turned her two piercing eyes elsewhere, whereon Jove's
+daughter Venus took Mars by the hand and led him away groaning
+all the time, for it was only with great difficulty that he had
+come to himself again. When Queen Juno saw her, she said to
+Minerva, "Look, daughter of aegis-bearing Jove, unweariable, that
+vixen Venus is again taking Mars through the crowd out of the
+battle; go after her at once."
+</para>
+
+<para>
+Thus she spoke. Minerva sped after Venus with a will, and made at
+her, striking her on the bosom with her strong hand so that she
+fell fainting to the ground, and there they both lay stretched at
+full length. Then Minerva vaunted over her saying, "May all who
+help the Trojans against the Argives prove just as redoubtable
+and stalwart as Venus did when she came across me while she was
+helping Mars. Had this been so, we should long since have ended
+the war by sacking the strong city of Ilius."
+</para>
+
+<para>
+Juno smiled as she listened. Meanwhile King Neptune turned to
+Apollo saying, "Phoebus, why should we keep each other at arm's
+length? it is not well, now that the others have begun fighting;
+it will be disgraceful to us if we return to Jove's
+bronze-floored mansion on Olympus without having fought each
+other; therefore come on, you are the younger of the two, and I
+ought not to attack you, for I am older and have had more
+experience. Idiot, you have no sense, and forget how we two alone
+of all the gods fared hardly round about Ilius when we came from
+Jove's house and worked for Laomedon a whole year at a stated
+wage and he gave us his orders. I built the Trojans the wall
+about their city, so wide and fair that it might be impregnable,
+while you, Phoebus, herded cattle for him in the dales of many
+valleyed Ida. When, however, the glad hours brought round the
+time of payment, mighty Laomedon robbed us of all our hire and
+sent us off with nothing but abuse. He threatened to bind us hand
+and foot and sell us over into some distant island. He tried,
+moreover, to cut off the ears of both of us, so we went away in a
+rage, furious about the payment he had promised us, and yet
+withheld; in spite of all this, you are now showing favour to his
+people, and will not join us in compassing the utter ruin of the
+proud Trojans with their wives and children."
+</para>
+
+<para>
+And King Apollo answered, "Lord of the earthquake, you would have
+no respect for me if I were to fight you about a pack of
+miserable mortals, who come out like leaves in summer and eat the
+fruit of the field, and presently fall lifeless to the ground.
+Let us stay this fighting at once and let them settle it among
+themselves."
+</para>
+
+<para>
+He turned away as he spoke, for he would lay no hand on the
+brother of his own father. But his sister the huntress Diana,
+patroness of wild beasts, was very angry with him and said, "So
+you would fly, Far-Darter, and hand victory over to Neptune with
+a cheap vaunt to boot. Baby, why keep your bow thus idle? Never
+let me again hear you bragging in my father's house, as you have
+often done in the presence of the immortals, that you would stand
+up and fight with Neptune."
+</para>
+
+<para>
+Apollo made her no answer, but Jove's august queen was angry and
+upbraided her bitterly. "Bold vixen," she cried, "how dare you
+cross me thus? For all your bow you will find it hard to hold
+your own against me. Jove made you as a lion among women, and
+lets you kill them whenever you choose. You will find it better
+to chase wild beasts and deer upon the mountains than to fight
+those who are stronger than you are. If you would try war, do so,
+and find out by pitting yourself against me, how far stronger I
+am than you are."
+</para>
+
+<para>
+She caught both Diana's wrists with her left hand as she spoke,
+and with her right she took the bow from her shoulders, and
+laughed as she beat her with it about the ears while Diana
+wriggled and writhed under her blows. Her swift arrows were shed
+upon the ground, and she fled weeping from under Juno's hand as a
+dove that flies before a falcon to the cleft of some hollow rock,
+when it is her good fortune to escape. Even so did she fly
+weeping away, leaving her bow and arrows behind her.
+</para>
+
+<para>
+Then the slayer of Argus, guide and guardian, said to Leto,
+"Leto, I shall not fight you; it is ill to come to blows with any
+of Jove's wives. Therefore boast as you will among the immortals
+that you worsted me in fair fight."
+</para>
+
+<para>
+Leto then gathered up Diana's bow and arrows that had fallen
+about amid the whirling dust, and when she had got them she made
+all haste after her daughter. Diana had now reached Jove's
+bronze-floored mansion on Olympus, and sat herself down with many
+tears on the knees of her father, while her ambrosial raiment was
+quivering all about her. The son of Saturn drew her towards him,
+and laughing pleasantly the while began to question her saying,
+"Which of the heavenly beings, my dear child, has been treating
+you in this cruel manner, as though you had been misconducting
+yourself in the face of everybody?" and the fair-crowned goddess
+of the chase answered, "It was your wife Juno, father, who has
+been beating me; it is always her doing when there is any
+quarrelling among the immortals."
+</para>
+
+<para>
+Thus did they converse, and meanwhile Phoebus Apollo entered the
+strong city of Ilius, for he was uneasy lest the wall should not
+hold out and the Danaans should take the city then and there,
+before its hour had come; but the rest of the ever-living gods
+went back, some angry and some triumphant to Olympus, where they
+took their seats beside Jove lord of the storm cloud, while
+Achilles still kept on dealing out death alike on the Trojans and
+on their horses. As when the smoke from some burning city ascends
+to heaven when the anger of the gods has kindled it--there is
+then toil for all, and sorrow for not a few--even so did Achilles
+bring toil and sorrow on the Trojans.
+</para>
+
+<para>
+Old King Priam stood on a high tower of the wall looking down on
+huge Achilles as the Trojans fled panic-stricken before him, and
+there was none to help them. Presently he came down from off the
+tower and with many a groan went along the wall to give orders to
+the brave warders of the gate. "Keep the gates," said he, "wide
+open till the people come flying into the city, for Achilles is
+hard by and is driving them in rout before him. I see we are in
+great peril. As soon as our people are inside and in safety,
+close the strong gates for I fear lest that terrible man should
+come bounding inside along with the others."
+</para>
+
+<para>
+As he spoke they drew back the bolts and opened the gates, and
+when these were opened there was a haven of refuge for the
+Trojans. Apollo then came full speed out of the city to meet them
+and protect them. Right for the city and the high wall, parched
+with thirst and grimy with dust, still they fied on, with
+Achilles wielding his spear furiously behind them. For he was as
+one possessed, and was thirsting after glory.
+</para>
+
+<para>
+Then had the sons of the Achaeans taken the lofty gates of Troy
+if Apollo had not spurred on Agenor, valiant and noble son to
+Antenor. He put courage into his heart, and stood by his side to
+guard him, leaning against a beech tree and shrouded in thick
+darkness. When Agenor saw Achilles he stood still and his heart
+was clouded with care. "Alas," said he to himself in his dismay,
+"if I fly before mighty Achilles, and go where all the others are
+being driven in rout, he will none the less catch me and kill me
+for a coward. How would it be were I to let Achilles drive the
+others before him, and then fly from the wall to the plain that
+is behind Ilius till I reach the spurs of Ida and can hide in the
+underwood that is thereon? I could then wash the sweat from off
+me in the river and in the evening return to Ilius. But why
+commune with myself in this way? Like enough he would see me as I
+am hurrying from the city over the plain, and would speed after
+me till he had caught me--I should stand no chance against him,
+for he is mightiest of all mankind. What, then, if I go out and
+meet him in front of the city? His flesh too, I take it, can be
+pierced by pointed bronze. Life is the same in one and all, and
+men say that he is but mortal despite the triumph that Jove son
+of Saturn vouchsafes him."
+</para>
+
+<para>
+So saying he stood on his guard and awaited Achilles, for he was
+now fain to fight him. As a leopardess that bounds from out a
+thick covert to attack a hunter--she knows no fear and is not
+dismayed by the baying of the hounds; even though the man be too
+quick for her and wound her either with thrust or spear, still,
+though the spear has pierced her she will not give in till she
+has either caught him in her grip or been killed outright--even
+so did noble Agenor son of Antenor refuse to fly till he had made
+trial of Achilles, and took aim at him with his spear, holding
+his round shield before him and crying with a loud voice. "Of a
+truth," said he, "noble Achilles, you deem that you shall this
+day sack the city of the proud Trojans. Fool, there will be
+trouble enough yet before it, for there is many a brave man of us
+still inside who will stand in front of our dear parents with our
+wives and children, to defend Ilius. Here therefore, huge and
+mighty warrior though you be, here shall you die."
+</para>
+
+<para>
+As he spoke his strong hand hurled his javelin from him, and the
+spear struck Achilles on the leg beneath the knee; the greave of
+newly wrought tin rang loudly, but the spear recoiled from the
+body of him whom it had struck, and did not pierce it, for the
+gods gift stayed it. Achilles in his turn attacked noble Agenor,
+but Apollo would not vouchsafe him glory, for he snatched Agenor
+away and hid him in a thick mist, sending him out of the battle
+unmolested Then he craftily drew the son of Peleus away from
+going after the host, for he put on the semblance of Agenor and
+stood in front of Achilles, who ran towards him to give him chase
+and pursued him over the corn lands of the plain, turning him
+towards the deep waters of the river Scamander. Apollo ran but a
+little way before him and beguiled Achilles by making him think
+all the time that he was on the point of overtaking him.
+Meanwhile the rabble of routed Trojans was thankful to crowd
+within the city till their numbers thronged it; no longer did
+they dare wait for one another outside the city walls, to learn
+who had escaped and who were fallen in fight, but all whose feet
+and knees could still carry them poured pell-mell into the town.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK XXII</title>
+
+<para>
+THUS the Trojans in the city, scared like fawns, wiped the sweat
+from off them and drank to quench their thirst, leaning against
+the goodly battlements, while the Achaeans with their shields
+laid upon their shoulders drew close up to the walls. But stern
+fate bade Hector stay where he was before Ilius and the Scaean
+gates. Then Phoebus Apollo spoke to the son of Peleus saying,
+"Why, son of Peleus, do you, who are but man, give chase to me
+who am immortal? Have you not yet found out that it is a god whom
+you pursue so furiously? You did not harass the Trojans whom you
+had routed, and now they are within their walls, while you have
+been decoyed hither away from them. Me you cannot kill, for death
+can take no hold upon me."
+</para>
+
+<para>
+Achilles was greatly angered and said, "You have baulked me,
+Far-Darter, most malicious of all gods, and have drawn me away
+from the wall, where many another man would have bitten the dust
+ere he got within Ilius; you have robbed me of great glory and
+have saved the Trojans at no risk to yourself, for you have
+nothing to fear, but I would indeed have my revenge if it were in
+my power to do so."
+</para>
+
+<para>
+On this, with fell intent he made towards the city, and as the
+winning horse in a chariot race strains every nerve when he is
+flying over the plain, even so fast and furiously did the limbs
+of Achilles bear him onwards. King Priam was first to note him as
+he scoured the plain, all radiant as the star which men call
+Orion's Hound, and whose beams blaze forth in time of harvest
+more brilliantly than those of any other that shines by night;
+brightest of them all though he be, he yet bodes ill for mortals,
+for he brings fire and fever in his train--even so did Achilles'
+armour gleam on his breast as he sped onwards. Priam raised a cry
+and beat his head with his hands as he lifted them up and shouted
+out to his dear son, imploring him to return; but Hector still
+stayed before the gates, for his heart was set upon doing battle
+with Achilles. The old man reached out his arms towards him and
+bade him for pity's sake come within the walls. "Hector," he
+cried, "my son, stay not to face this man alone and unsupported,
+or you will meet death at the hands of the son of Peleus, for he
+is mightier than you. Monster that he is; would indeed that the
+gods loved him no better than I do, for so, dogs and vultures
+would soon devour him as he lay stretched on earth, and a load of
+grief would be lifted from my heart, for many a brave son has he
+reft from me, either by killing them or selling them away in the
+islands that are beyond the sea: even now I miss two sons from
+among the Trojans who have thronged within the city, Lycaon and
+Polydorus, whom Laothoe peeress among women bore me. Should they
+be still alive and in the hands of the Achaeans, we will ransom
+them with gold and bronze, of which we have store, for the old
+man Altes endowed his daughter richly; but if they are already
+dead and in the house of Hades, sorrow will it be to us two who
+were their parents; albeit the grief of others will be more
+short-lived unless you too perish at the hands of Achilles. Come,
+then, my son, within the city, to be the guardian of Trojan men
+and Trojan women, or you will both lose your own life and afford
+a mighty triumph to the son of Peleus. Have pity also on your
+unhappy father while life yet remains to him--on me, whom the son
+of Saturn will destroy by a terrible doom on the threshold of old
+age, after I have seen my sons slain and my daughters haled away
+as captives, my bridal chambers pillaged, little children dashed
+to earth amid the rage of battle, and my sons' wives dragged away
+by the cruel hands of the Achaeans; in the end fierce hounds will
+tear me in pieces at my own gates after some one has beaten the
+life out of my body with sword or spear-hounds that I myself
+reared and fed at my own table to guard my gates, but who will
+yet lap my blood and then lie all distraught at my doors. When a
+young man falls by the sword in battle, he may lie where he is
+and there is nothing unseemly; let what will be seen, all is
+honourable in death, but when an old man is slain there is
+nothing in this world more pitiable than that dogs should defile
+his grey hair and beard and all that men hide for shame."
+</para>
+
+<para>
+The old man tore his grey hair as he spoke, but he moved not the
+heart of Hector. His mother hard by wept and moaned aloud as she
+bared her bosom and pointed to the breast which had suckled him.
+"Hector," she cried, weeping bitterly the while, "Hector, my son,
+spurn not this breast, but have pity upon me too: if I have ever
+given you comfort from my own bosom, think on it now, dear son,
+and come within the wall to protect us from this man; stand not
+without to meet him. Should the wretch kill you, neither I nor
+your richly dowered wife shall ever weep, dear offshoot of
+myself, over the bed on which you lie, for dogs will devour you
+at the ships of the Achaeans."
+</para>
+
+<para>
+Thus did the two with many tears implore their son, but they
+moved not the heart of Hector, and he stood his ground awaiting
+huge Achilles as he drew nearer towards him. As serpent in its
+den upon the mountains, full fed with deadly poisons, waits for
+the approach of man--he is filled with fury and his eyes glare
+terribly as he goes writhing round his den--even so Hector leaned
+his shield against a tower that jutted out from the wall and
+stood where he was, undaunted.
+</para>
+
+<para>
+"Alas," said he to himself in the heaviness of his heart, "if I
+go within the gates, Polydamas will be the first to heap reproach
+upon me, for it was he that urged me to lead the Trojans back to
+the city on that awful night when Achilles again came forth
+against us. I would not listen, but it would have been indeed
+better if I had done so. Now that my folly has destroyed the
+host, I dare not look Trojan men and Trojan women in the face,
+lest a worse man should say, 'Hector has ruined us by his
+self-confidence.' Surely it would be better for me to return
+after having fought Achilles and slain him, or to die gloriously
+here before the city. What, again, if I were to lay down my
+shield and helmet, lean my spear against the wall and go straight
+up to noble Achilles? What if I were to promise to give up Helen,
+who was the fountainhead of all this war, and all the treasure
+that Alexandrus brought with him in his ships to Troy, aye, and
+to let the Achaeans divide the half of everything that the city
+contains among themselves? I might make the Trojans, by the
+mouths of their princes, take a solemn oath that they would hide
+nothing, but would divide into two shares all that is within the
+city--but why argue with myself in this way? Were I to go up to
+him he would show me no kind of mercy; he would kill me then and
+there as easily as though I were a woman, when I had off my
+armour. There is no parleying with him from some rock or oak
+tree as young men and maidens prattle with one another. Better
+fight him at once, and learn to which of us Jove will vouchsafe
+victory."
+</para>
+
+<para>
+Thus did he stand and ponder, but Achilles came up to him as it
+were Mars himself, plumed lord of battle. From his right shoulder
+he brandished his terrible spear of Pelian ash, and the bronze
+gleamed around him like flashing fire or the rays of the rising
+sun. Fear fell upon Hector as he beheld him, and he dared not
+stay longer where he was but fled in dismay from before the
+gates, while Achilles darted after him at his utmost speed. As a
+mountain falcon, swiftest of all birds, swoops down upon some
+cowering dove--the dove flies before him but the falcon with a
+shrill scream follows close after, resolved to have her--even so
+did Achilles make straight for Hector with all his might, while
+Hector fled under the Trojan wall as fast as his limbs could take
+him.
+</para>
+
+<para>
+On they flew along the waggon-road that ran hard by under the
+wall, past the lookout station, and past the weather-beaten wild
+fig-tree, till they came to two fair springs which feed the river
+Scamander. One of these two springs is warm, and steam rises from
+it as smoke from a burning fire, but the other even in summer is
+as cold as hail or snow, or the ice that forms on water. Here,
+hard by the springs, are the goodly washing-troughs of stone,
+where in the time of peace before the coming of the Achaeans the
+wives and fair daughters of the Trojans used to wash their
+clothes. Past these did they fly, the one in front and the other
+giving chase behind him: good was the man that fled, but better
+far was he that followed after, and swiftly indeed did they run,
+for the prize was no mere beast for sacrifice or bullock's hide,
+as it might be for a common foot-race, but they ran for the life
+of Hector. As horses in a chariot race speed round the
+turning-posts when they are running for some great prize--a
+tripod or woman--at the games in honour of some dead hero, so did
+these two run full speed three times round the city of Priam. All
+the gods watched them, and the sire of gods and men was the first
+to speak.
+</para>
+
+<para>
+"Alas," said he, "my eyes behold a man who is dear to me being
+pursued round the walls of Troy; my heart is full of pity for
+Hector, who has burned the thigh-bones of many a heifer in my
+honour, one while on the crests of many-valleyed Ida, and again
+on the citadel of Troy; and now I see noble Achilles in full
+pursuit of him round the city of Priam. What say you? Consider
+among yourselves and decide whether we shall now save him or let
+him fall, valiant though he be, before Achilles, son of Peleus."
+</para>
+
+<para>
+Then Minerva said, "Father, wielder of the lightning, lord of
+cloud and storm, what mean you? Would you pluck this mortal whose
+doom has long been decreed out of the jaws of death? Do as you
+will, but we others shall not be of a mind with you."
+</para>
+
+<para>
+And Jove answered, "My child, Trito-born, take heart. I did not
+speak in full earnest, and I will let you have your way. Do
+without let or hindrance as you are minded."
+</para>
+
+<para>
+Thus did he urge Minerva who was already eager, and down she
+darted from the topmost summits of Olympus.
+</para>
+
+<para>
+Achilles was still in full pursuit of Hector, as a hound chasing
+a fawn which he has started from its covert on the mountains, and
+hunts through glade and thicket. The fawn may try to elude him by
+crouching under cover of a bush, but he will scent her out and
+follow her up until he gets her--even so there was no escape for
+Hector from the fleet son of Peleus. Whenever he made a set to
+get near the Dardanian gates and under the walls, that his people
+might help him by showering down weapons from above, Achilles
+would gain on him and head him back towards the plain, keeping
+himself always on the city side. As a man in a dream who fails to
+lay hands upon another whom he is pursuing--the one cannot escape
+nor the other overtake--even so neither could Achilles come up
+with Hector, nor Hector break away from Achilles; nevertheless he
+might even yet have escaped death had not the time come when
+Apollo, who thus far had sustained his strength and nerved his
+running, was now no longer to stay by him. Achilles made signs to
+the Achaean host, and shook his head to show that no man was to
+aim a dart at Hector, lest another might win the glory of having
+hit him and he might himself come in second. Then, at last, as
+they were nearing the fountains for the fourth time, the father
+of all balanced his golden scales and placed a doom in each of
+them, one for Achilles and the other for Hector. As he held the
+scales by the middle, the doom of Hector fell down deep into the
+house of Hades--and then Phoebus Apollo left him. Thereon Minerva
+went close up to the son of Peleus and said, "Noble Achilles,
+favoured of heaven, we two shall surely take back to the ships a
+triumph for the Achaeans by slaying Hector, for all his lust of
+battle. Do what Apollo may as he lies grovelling before his
+father, aegis-bearing Jove, Hector cannot escape us longer. Stay
+here and take breath, while I go up to him and persuade him to
+make a stand and fight you."
+</para>
+
+<para>
+Thus spoke Minerva. Achilles obeyed her gladly, and stood still,
+leaning on his bronze-pointed ashen spear, while Minerva left him
+and went after Hector in the form and with the voice of
+Deiphobus. She came close up to him and said, "Dear brother, I
+see you are hard pressed by Achilles who is chasing you at full
+speed round the city of Priam, let us await his onset and stand
+on our defence."
+</para>
+
+<para>
+And Hector answered, "Deiphobus, you have always been dearest to
+me of all my brothers, children of Hecuba and Priam, but
+henceforth I shall rate you yet more highly, inasmuch as you have
+ventured outside the wall for my sake when all the others remain
+inside."
+</para>
+
+<para>
+Then Minerva said, "Dear brother, my father and mother went down
+on their knees and implored me, as did all my comrades, to remain
+inside, so great a fear has fallen upon them all; but I was in an
+agony of grief when I beheld you; now, therefore, let us two make
+a stand and fight, and let there be no keeping our spears in
+reserve, that we may learn whether Achilles shall kill us and
+bear off our spoils to the ships, or whether he shall fall before
+you."
+</para>
+
+<para>
+Thus did Minerva inveigle him by her cunning, and when the two
+were now close to one another great Hector was first to speak. "I
+will-no longer fly you, son of Peleus," said he, "as I have been
+doing hitherto. Three times have I fled round the mighty city of
+Priam, without daring to withstand you, but now, let me either
+slay or be slain, for I am in the mind to face you. Let us, then,
+give pledges to one another by our gods, who are the fittest
+witnesses and guardians of all covenants; let it be agreed
+between us that if Jove vouchsafes me the longer stay and I take
+your life, I am not to treat your dead body in any unseemly
+fashion, but when I have stripped you of your armour, I am to
+give up your body to the Achaeans. And do you likewise."
+</para>
+
+<para>
+Achilles glared at him and answered, "Fool, prate not to me about
+covenants. There can be no covenants between men and lions,
+wolves and lambs can never be of one mind, but hate each other
+out and out an through. Therefore there can be no understanding
+between you and me, nor may there be any covenants between us,
+till one or other shall fall and glut grim Mars with his life's
+blood. Put forth all your strength; you have need now to prove
+yourself indeed a bold soldier and man of war. You have no more
+chance, and Pallas Minerva will forthwith vanquish you by my
+spear: you shall now pay me in full for the grief you have caused
+me on account of my comrades whom you have killed in battle."
+</para>
+
+<para>
+He poised his spear as he spoke and hurled it. Hector saw it
+coming and avoided it; he watched it and crouched down so that it
+flew over his head and stuck in the ground beyond; Minerva then
+snatched it up and gave it back to Achilles without Hector's
+seeing her; Hector thereon said to the son of Peleus, "You have
+missed your aim, Achilles, peer of the gods, and Jove has not yet
+revealed to you the hour of my doom, though you made sure that he
+had done so. You were a false-tongued liar when you deemed that I
+should forget my valour and quail before you. You shall not drive
+spear into the back of a runaway--drive it, should heaven so
+grant you power, drive it into me as I make straight towards you;
+and now for your own part avoid my spear if you can--would that
+you might receive the whole of it into your body; if you were
+once dead the Trojans would find the war an easier matter, for it
+is you who have harmed them most."
+</para>
+
+<para>
+He poised his spear as he spoke and hurled it. His aim was true
+for he hit the middle of Achilles' shield, but the spear
+rebounded from it, and did not pierce it. Hector was angry when
+he saw that the weapon had sped from his hand in vain, and stood
+there in dismay for he had no second spear. With a loud cry he
+called Deiphobus and asked him for one, but there was no man;
+then he saw the truth and said to himself, "Alas! the gods have
+lured me on to my destruction. I deemed that the hero Deiphobus
+was by my side, but he is within the wall, and Minerva has
+inveigled me; death is now indeed exceedingly near at hand and
+there is no way out of it--for so Jove and his son Apollo the
+far-darter have willed it, though heretofore they have been ever
+ready to protect me. My doom has come upon me; let me not then
+die ingloriously and without a struggle, but let me first do some
+great thing that shall be told among men hereafter."
+</para>
+
+<para>
+As he spoke he drew the keen blade that hung so great and strong
+by his side, and gathering himself together be sprang on Achilles
+like a soaring eagle which swoops down from the clouds on to some
+lamb or timid hare--even so did Hector brandish his sword and
+spring upon Achilles. Achilles mad with rage darted towards him,
+with his wondrous shield before his breast, and his gleaming
+helmet, made with four layers of metal, nodding fiercely forward.
+The thick tresses of gold with which Vulcan had crested the
+helmet floated round it, and as the evening star that shines
+brighter than all others through the stillness of night, even
+such was the gleam of the spear which Achilles poised in his
+right hand, fraught with the death of noble Hector. He eyed his
+fair flesh over and over to see where he could best wound it, but
+all was protected by the goodly armour of which Hector had
+spoiled Patroclus after he had slain him, save only the throat
+where the collar-bones divide the neck from the shoulders, and
+this is a most deadly place: here then did Achilles strike him as
+he was coming on towards him, and the point of his spear went
+right through the fleshy part of the neck, but it did not sever
+his windpipe so that he could still speak. Hector fell headlong,
+and Achilles vaunted over him saying, "Hector, you deemed that
+you should come off scatheless when you were spoiling Patroclus,
+and recked not of myself who was not with him. Fool that you
+were: for I, his comrade, mightier far than he, was still left
+behind him at the ships, and now I have laid you low. The
+Achaeans shall give him all due funeral rites, while dogs and
+vultures shall work their will upon yourself."
+</para>
+
+<para>
+Then Hector said, as the life ebbed out of him, "I pray you by
+your life and knees, and by your parents, let not dogs devour me
+at the ships of the Achaeans, but accept the rich treasure of
+gold and bronze which my father and mother will offer you, and
+send my body home, that the Trojans and their wives may give me
+my dues of fire when I am dead."
+</para>
+
+<para>
+Achilles glared at him and answered, "Dog, talk not to me neither
+of knees nor parents; would that I could be as sure of being able
+to cut your flesh into pieces and eat it raw, for the ill you
+have done me, as I am that nothing shall save you from the
+dogs--it shall not be, though they bring ten or twenty-fold
+ransom and weigh it out for me on the spot, with promise of yet
+more hereafter. Though Priam son of Dardanus should bid them
+offer me your weight in gold, even so your mother shall never lay
+you out and make lament over the son she bore, but dogs and
+vultures shall eat you utterly up."
+</para>
+
+<para>
+Hector with his dying breath then said, "I know you what you are,
+and was sure that I should not move you, for your heart is hard
+as iron; look to it that I bring not heaven's anger upon you on
+the day when Paris and Phoebus Apollo, valiant though you be,
+shall slay you at the Scaean gates."
+</para>
+
+<para>
+When he had thus said the shrouds of death enfolded him, whereon
+his soul went out of him and flew down to the house of Hades,
+lamenting its sad fate that it should enjoy youth and strength no
+longer. But Achilles said, speaking to the dead body, "Die; for
+my part I will accept my fate whensoever Jove and the other gods
+see fit to send it."
+</para>
+
+<para>
+As he spoke he drew his spear from the body and set it on one
+side; then he stripped the blood-stained armour from Hector's
+shoulders while the other Achaeans came running up to view his
+wondrous strength and beauty; and no one came near him without
+giving him a fresh wound. Then would one turn to his neighbour
+and say, "It is easier to handle Hector now than when he was
+flinging fire on to our ships" and as he spoke he would thrust
+his spear into him anew.
+</para>
+
+<para>
+When Achilles had done spoiling Hector of his armour, he stood
+among the Argives and said, "My friends, princes and counsellors
+of the Argives, now that heaven has vouchsafed us to overcome
+this man, who has done us more hurt than all the others together,
+consider whether we should not attack the city in force, and
+discover in what mind the Trojans may be. We should thus learn
+whether they will desert their city now that Hector has fallen,
+or will still hold out even though he is no longer living. But
+why argue with myself in this way, while Patroclus is still lying
+at the ships unburied, and unmourned--he whom I can never forget
+so long as I am alive and my strength fails not? Though men
+forget their dead when once they are within the house of Hades,
+yet not even there will I forget the comrade whom I have lost.
+Now, therefore, Achaean youths, let us raise the song of victory
+and go back to the ships taking this man along with us; for we
+have achieved a mighty triumph and have slain noble Hector to
+whom the Trojans prayed throughout their city as though he were a
+god."
+</para>
+
+<para>
+On this he treated the body of Hector with contumely: he pierced
+the sinews at the back of both his feet from heel to ancle and
+passed thongs of ox-hide through the slits he had made: thus he
+made the body fast to his chariot, letting the head trail upon
+the ground. Then when he had put the goodly armour on the chariot
+and had himself mounted, he lashed his horses on and they flew
+forward nothing loth. The dust rose from Hector as he was being
+dragged along, his dark hair flew all abroad, and his head once
+so comely was laid low on earth, for Jove had now delivered him
+into the hands of his foes to do him outrage in his own land.
+</para>
+
+<para>
+Thus was the head of Hector being dishonoured in the dust. His
+mother tore her hair, and flung her veil from her with a loud cry
+as she looked upon her son. His father made piteous moan, and
+throughout the city the people fell to weeping and wailing. It
+was as though the whole of frowning Ilius was being smirched with
+fire. Hardly could the people hold Priam back in his hot haste to
+rush without the gates of the city. He grovelled in the mire and
+besought them, calling each one of them by his name. "Let be, my
+friends," he cried, "and for all your sorrow, suffer me to go
+single-handed to the ships of the Achaeans. Let me beseech this
+cruel and terrible man, if maybe he will respect the feeling of
+his fellow-men, and have compassion on my old age. His own father
+is even such another as myself--Peleus, who bred him and reared
+him to be the bane of us Trojans, and of myself more than of all
+others. Many a son of mine has he slain in the flower of his
+youth, and yet, grieve for these as I may, I do so for one--
+Hector--more than for them all, and the bitterness of my sorrow
+will bring me down to the house of Hades. Would that he had died
+in my arms, for so both his ill-starred mother who bore him, and
+myself, should have had the comfort of weeping and mourning over
+him."
+</para>
+
+<para>
+Thus did he speak with many tears, and all the people of the city
+joined in his lament. Hecuba then raised the cry of wailing among
+the Trojans. "Alas, my son," she cried, "what have I left to live
+for now that you are no more? Night and day did I glory in you
+throughout the city, for you were a tower of strength to all in
+Troy, and both men and women alike hailed you as a god. So long
+as you lived you were their pride, but now death and destruction
+have fallen upon you."
+</para>
+
+<para>
+Hector's wife had as yet heard nothing, for no one had come to
+tell her that her husband had remained without the gates. She was
+at her loom in an inner part of the house, weaving a double
+purple web, and embroidering it with many flowers. She told her
+maids to set a large tripod on the fire, so as to have a warm
+bath ready for Hector when he came out of battle; poor woman, she
+knew not that he was now beyond the reach of baths, and that
+Minerva had laid him low by the hands of Achilles. She heard the
+cry coming as from the wall, and trembled in every limb; the
+shuttle fell from her hands, and again she spoke to her
+waiting-women. "Two of you," she said, "come with me that I may
+learn what it is that has befallen; I heard the voice of my
+husband's honoured mother; my own heart beats as though it would
+come into my mouth and my limbs refuse to carry me; some great
+misfortune for Priam's children must be at hand. May I never live
+to hear it, but I greatly fear that Achilles has cut off the
+retreat of brave Hector and has chased him on to the plain where
+he was singlehanded; I fear he may have put an end to the
+reckless daring which possessed my husband, who would never
+remain with the body of his men, but would dash on far in front,
+foremost of them all in valour."
+</para>
+
+<para>
+Her heart beat fast, and as she spoke she flew from the house
+like a maniac, with her waiting-women following after. When she
+reached the battlements and the crowd of people, she stood
+looking out upon the wall, and saw Hector being borne away in
+front of the city--the horses dragging him without heed or care
+over the ground towards the ships of the Achaeans. Her eyes were
+then shrouded as with the darkness of night and she fell fainting
+backwards. She tore the attiring from her head and flung it from
+her, the frontlet and net with its plaited band, and the veil
+which golden Venus had given her on the day when Hector took her
+with him from the house of Eetion, after having given countless
+gifts of wooing for her sake. Her husband's sisters and the wives
+of his brothers crowded round her and supported her, for she was
+fain to die in her distraction; when she again presently breathed
+and came to herself, she sobbed and made lament among the Trojans
+saying, "Woe is me, O Hector; woe, indeed, that to share a common
+lot we were born, you at Troy in the house of Priam, and I at
+Thebes under the wooded mountain of Placus in the house of Eetion
+who brought me up when I was a child--ill-starred sire of an
+ill-starred daughter--would that he had never begotten me. You
+are now going into the house of Hades under the secret places of
+the earth, and you leave me a sorrowing widow in your house. The
+child, of whom you and I are the unhappy parents, is as yet a
+mere infant. Now that you are gone, O Hector, you can do nothing
+for him nor he for you. Even though he escape the horrors of this
+woeful war with the Achaeans, yet shall his life henceforth be
+one of labour and sorrow, for others will seize his lands. The
+day that robs a child of his parents severs him from his own
+kind; his head is bowed, his cheeks are wet with tears, and he
+will go about destitute among the friends of his father, plucking
+one by the cloak and another by the shirt. Some one or other of
+these may so far pity him as to hold the cup for a moment towards
+him and let him moisten his lips, but he must not drink enough to
+wet the roof of his mouth; then one whose parents are alive will
+drive him from the table with blows and angry words. 'Out with
+you,' he will say, 'you have no father here,' and the child will
+go crying back to his widowed mother--he, Astyanax, who erewhile
+would sit upon his father's knees, and have none but the
+daintiest and choicest morsels set before him. When he had played
+till he was tired and went to sleep, he would lie in a bed, in
+the arms of his nurse, on a soft couch, knowing neither want nor
+care, whereas now that he has lost his father his lot will be
+full of hardship--he, whom the Trojans name Astyanax, because
+you, O Hector, were the only defence of their gates and
+battlements. The wriggling writhing worms will now eat you at the
+ships, far from your parents, when the dogs have glutted
+themselves upon you. You will lie naked, although in your house
+you have fine and goodly raiment made by hands of women. This
+will I now burn; it is of no use to you, for you can never again
+wear it, and thus you will have respect shown you by the Trojans
+both men and women."
+</para>
+
+<para>
+In such wise did she cry aloud amid her tears, and the women
+joined in her lament.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK XXIII</title>
+
+<para>
+THUS did they make their moan throughout the city, while the
+Achaeans when they reached the Hellespont went back every man to
+his own ship. But Achilles would not let the Myrmidons go, and
+spoke to his brave comrades saying, "Myrmidons, famed horsemen
+and my own trusted friends, not yet, forsooth, let us unyoke, but
+with horse and chariot draw near to the body and mourn Patroclus,
+in due honour to the dead. When we have had full comfort of
+lamentation we will unyoke our horses and take supper all of us
+here."
+</para>
+
+<para>
+On this they all joined in a cry of wailing and Achilles led them
+in their lament. Thrice did they drive their chariots all
+sorrowing round the body, and Thetis stirred within them a still
+deeper yearning. The sands of the seashore and the men's armour
+were wet with their weeping, so great a minister of fear was he
+whom they had lost. Chief in all their mourning was the son of
+Peleus: he laid his bloodstained hand on the breast of his
+friend. "Fare well," he cried, "Patroclus, even in the house of
+Hades. I will now do all that I erewhile promised you; I will
+drag Hector hither and let dogs devour him raw; twelve noble sons
+of Trojans will I also slay before your pyre to avenge you."
+</para>
+
+<para>
+As he spoke he treated the body of noble Hector with contumely,
+laying it at full length in the dust beside the bier of
+Patroclus. The others then put off every man his armour, took the
+horses from their chariots, and seated themselves in great
+multitude by the ship of the fleet descendant of Aeacus, who
+thereon feasted them with an abundant funeral banquet. Many a
+goodly ox, with many a sheep and bleating goat did they butcher
+and cut up; many a tusked boar moreover, fat and well-fed, did
+they singe and set to roast in the flames of Vulcan; and rivulets
+of blood flowed all round the place where the body was lying.
+</para>
+
+<para>
+Then the princes of the Achaeans took the son of Peleus to
+Agamemnon, but hardly could they persuade him to come with them,
+so wroth was he for the death of his comrade. As soon as they
+reached Agamemnon's tent they told the serving-men to set a large
+tripod over the fire in case they might persuade the son of
+Peleus to wash the clotted gore from this body, but he denied
+them sternly, and swore it with a solemn oath, saying, "Nay, by
+King Jove, first and mightiest of all gods, it is not meet that
+water should touch my body, till I have laid Patroclus on the
+flames, have built him a barrow, and shaved my head--for so long
+as I live no such second sorrow shall ever draw nigh me. Now,
+therefore, let us do all that this sad festival demands, but at
+break of day, King Agamemnon, bid your men bring wood, and
+provide all else that the dead may duly take into the realm of
+darkness; the fire shall thus burn him out of our sight the
+sooner, and the people shall turn again to their own labours."
+</para>
+
+<para>
+Thus did he speak, and they did even as he had said. They made
+haste to prepare the meal, they ate, and every man had his full
+share so that all were satisfied. As soon as they had had enough
+to eat and drink, the others went to their rest each in his own
+tent, but the son of Peleus lay grieving among his Myrmidons by
+the shore of the sounding sea, in an open place where the waves
+came surging in one after another. Here a very deep slumber took
+hold upon him and eased the burden of his sorrows, for his limbs
+were weary with chasing Hector round windy Ilius. Presently the
+sad spirit of Patroclus drew near him, like what he had been in
+stature, voice, and the light of his beaming eyes, clad, too, as
+he had been clad in life. The spirit hovered over his head and
+said--
+</para>
+
+<para>
+"You sleep, Achilles, and have forgotten me; you loved me living,
+but now that I am dead you think for me no further. Bury me with
+all speed that I may pass the gates of Hades; the ghosts, vain
+shadows of men that can labour no more, drive me away from them;
+they will not yet suffer me to join those that are beyond the
+river, and I wander all desolate by the wide gates of the house
+of Hades. Give me now your hand I pray you, for when you have
+once given me my dues of fire, never shall I again come forth out
+of the house of Hades. Nevermore shall we sit apart and take
+sweet counsel among the living; the cruel fate which was my
+birth-right has yawned its wide jaws around me--nay, you too
+Achilles, peer of gods, are doomed to die beneath the wall of the
+noble Trojans.
+</para>
+
+<para>
+"One prayer more will I make you, if you will grant it; let not
+my bones be laid apart from yours, Achilles, but with them; even
+as we were brought up together in your own home, what time
+Menoetius brought me to you as a child from Opoeis because by a
+sad spite I had killed the son of Amphidamas--not of set purpose,
+but in childish quarrel over the dice. The knight Peleus took me
+into his house, entreated me kindly, and named me to be your
+squire; therefore let our bones lie in but a single urn, the
+two-handled golden vase given to you by your mother."
+</para>
+
+<para>
+And Achilles answered, "Why, true heart, are you come hither to
+lay these charges upon me? will of my own self do all as you have
+bidden me. Draw closer to me, let us once more throw our arms
+around one another, and find sad comfort in the sharing of our
+sorrows."
+</para>
+
+<para>
+He opened his arms towards him as he spoke and would have clasped
+him in them, but there was nothing, and the spirit vanished as a
+vapour, gibbering and whining into the earth. Achilles sprang to
+his feet, smote his two hands, and made lamentation saying, "Of a
+truth even in the house of Hades there are ghosts and phantoms
+that have no life in them; all night long the sad spirit of
+Patroclus has hovered over head making piteous moan, telling me
+what I am to do for him, and looking wondrously like himself."
+</para>
+
+<para>
+Thus did he speak and his words set them all weeping and mourning
+about the poor dumb dead, till rosy-fingered morn appeared. Then
+King Agamemnon sent men and mules from all parts of the camp, to
+bring wood, and Meriones, squire to Idomeneus, was in charge over
+them. They went out with woodmen's axes and strong ropes in their
+hands, and before them went the mules. Up hill and down dale did
+they go, by straight ways and crooked, and when they reached the
+heights of many-fountained Ida, they laid their axes to the roots
+of many a tall branching oak that came thundering down as they
+felled it. They split the trees and bound them behind the mules,
+which then wended their way as they best could through the thick
+brushwood on to the plain. All who had been cutting wood bore
+logs, for so Meriones squire to Idomeneus had bidden them, and
+they threw them down in a line upon the seashore at the place
+where Achilles would make a mighty monument for Patroclus and for
+himself.
+</para>
+
+<para>
+When they had thrown down their great logs of wood over the whole
+ground, they stayed all of them where they were, but Achilles
+ordered his brave Myrmidons to gird on their armour, and to yoke
+each man his horses; they therefore rose, girded on their armour
+and mounted each his chariot--they and their charioteers with
+them. The chariots went before, and they that were on foot
+followed as a cloud in their tens of thousands after. In the
+midst of them his comrades bore Patroclus and covered him with
+the locks of their hair which they cut off and threw upon his
+body. Last came Achilles with his head bowed for sorrow, so noble
+a comrade was he taking to the house of Hades.
+</para>
+
+<para>
+When they came to the place of which Achilles had told them they
+laid the body down and built up the wood. Achilles then bethought
+him of another matter. He went a space away from the pyre, and
+cut off the yellow lock which he had let grow for the river
+Spercheius. He looked all sorrowfully out upon the dark sea, and
+said, "Spercheius, in vain did my father Peleus vow to you that
+when I returned home to my loved native land I should cut off
+this lock and offer you a holy hecatomb; fifty she-goats was I to
+sacrifice to you there at your springs, where is your grove and
+your altar fragrant with burnt-offerings. Thus did my father vow,
+but you have not fulfilled his prayer; now, therefore, that I
+shall see my home no more, I give this lock as a keepsake to the
+hero Patroclus."
+</para>
+
+<para>
+As he spoke he placed the lock in the hands of his dear comrade,
+and all who stood by were filled with yearning and lamentation.
+The sun would have gone down upon their mourning had not Achilles
+presently said to Agamemnon, "Son of Atreus, for it is to you
+that the people will give ear, there is a time to mourn and a
+time to cease from mourning; bid the people now leave the pyre
+and set about getting their dinners: we, to whom the dead is
+dearest, will see to what is wanted here, and let the other
+princes also stay by me."
+</para>
+
+<para>
+When King Agamemnon heard this he dismissed the people to their
+ships, but those who were about the dead heaped up wood and built
+a pyre a hundred feet this way and that; then they laid the dead
+all sorrowfully upon the top of it. They flayed and dressed many
+fat sheep and oxen before the pyre, and Achilles took fat from
+all of them and wrapped the body therein from head to foot,
+heaping the flayed carcases all round it. Against the bier he
+leaned two-handled jars of honey and unguents; four proud horses
+did he then cast upon the pyre, groaning the while he did so. The
+dead hero had had house-dogs; two of them did Achilles slay and
+threw upon the pyre; he also put twelve brave sons of noble
+Trojans to the sword and laid them with the rest, for he was full
+of bitterness and fury. Then he committed all to the resistless
+and devouring might of the fire; he groaned aloud and called on
+his dead comrade by name. "Fare well," he cried, "Patroclus, even
+in the house of Hades; I am now doing all that I have promised
+you. Twelve brave sons of noble Trojans shall the flames consume
+along with yourself, but dogs, not fire, shall devour the flesh
+of Hector son of Priam."
+</para>
+
+<para>
+Thus did he vaunt, but the dogs came not about the body of
+Hector, for Jove's daughter Venus kept them off him night and
+day, and anointed him with ambrosial oil of roses that his flesh
+might not be torn when Achilles was dragging him about. Phoebus
+Apollo moreover sent a dark cloud from heaven to earth, which
+gave shade to the whole place where Hector lay, that the heat of
+the sun might not parch his body.
+</para>
+
+<para>
+Now the pyre about dead Patroclus would not kindle. Achilles
+therefore bethought him of another matter; he went apart and
+prayed to the two winds Boreas and Zephyrus vowing them goodly
+offerings. He made them many drink-offerings from the golden cup
+and besought them to come and help him that the wood might make
+haste to kindle and the dead bodies be consumed. Fleet Iris heard
+him praying and started off to fetch the winds. They were holding
+high feast in the house of boisterous Zephyrus when Iris came
+running up to the stone threshold of the house and stood there,
+but as soon as they set eyes on her they all came towards her and
+each of them called her to him, but Iris would not sit down. "I
+cannot stay," she said, "I must go back to the streams of Oceanus
+and the land of the Ethiopians who are offering hecatombs to the
+immortals, and I would have my share; but Achilles prays that
+Boreas and shrill Zephyrus will come to him, and he vows them
+goodly offerings; he would have you blow upon the pyre of
+Patroclus for whom all the Achaeans are lamenting."
+</para>
+
+<para>
+With this she left them, and the two winds rose with a cry that
+rent the air and swept the clouds before them. They blew on and
+on until they came to the sea, and the waves rose high beneath
+them, but when they reached Troy they fell upon the pyre till the
+mighty flames roared under the blast that they blew. All night
+long did they blow hard and beat upon the fire, and all night
+long did Achilles grasp his double cup, drawing wine from a
+mixing-bowl of gold, and calling upon the spirit of dead
+Patroclus as he poured it upon the ground until the earth was
+drenched. As a father mourns when he is burning the bones of his
+bridegroom son whose death has wrung the hearts of his parents,
+even so did Achilles mourn while burning the body of his comrade,
+pacing round the bier with piteous groaning and lamentation.
+</para>
+
+<para>
+At length as the Morning Star was beginning to herald the light
+which saffron-mantled Dawn was soon to suffuse over the sea, the
+flames fell and the fire began to die. The winds then went home
+beyond the Thracian sea, which roared and boiled as they swept
+over it. The son of Peleus now turned away from the pyre and lay
+down, overcome with toil, till he fell into a sweet slumber.
+Presently they who were about the son of Atreus drew near in a
+body, and roused him with the noise and tramp of their coming. He
+sat upright and said, "Son of Atreus, and all other princes of
+the Achaeans, first pour red wine everywhere upon the fire and
+quench it; let us then gather the bones of Patroclus son of
+Menoetius, singling them out with care; they are easily found,
+for they lie in the middle of the pyre, while all else, both men
+and horses, has been thrown in a heap and burned at the outer
+edge. We will lay the bones in a golden urn, in two layers of
+fat, against the time when I shall myself go down into the house
+of Hades. As for the barrow, labour not to raise a great one now,
+but such as is reasonable. Afterwards, let those Achaeans who may
+be left at the ships when I am gone, build it both broad and
+high."
+</para>
+
+<para>
+Thus he spoke and they obeyed the word of the son of Peleus.
+First they poured red wine upon the thick layer of ashes and
+quenched the fire. With many tears they singled out the whitened
+bones of their loved comrade and laid them within a golden urn in
+two layers of fat: they then covered the urn with a linen cloth
+and took it inside the tent. They marked off the circle where the
+barrow should be, made a foundation for it about the pyre, and
+forthwith heaped up the earth. When they had thus raised a mound
+they were going away, but Achilles stayed the people and made
+them sit in assembly. He brought prizes from the
+ships--cauldrons, tripods, horses and mules, noble oxen, women
+with fair girdles, and swart iron.
+</para>
+
+<para>
+The first prize he offered was for the chariot races--a woman
+skilled in all useful arts, and a three-legged cauldron that had
+ears for handles, and would hold twenty-two measures. This was
+for the man who came in first. For the second there was a
+six-year old mare, unbroken, and in foal to a he-ass; the third
+was to have a goodly cauldron that had never yet been on the
+fire; it was still bright as when it left the maker, and would
+hold four measures. The fourth prize was two talents of gold, and
+the fifth a two-handled urn as yet unsoiled by smoke. Then he
+stood up and spoke among the Argives saying--
+</para>
+
+<para>
+"Son of Atreus, and all other Achaeans, these are the prizes that
+lie waiting the winners of the chariot races. At any other time I
+should carry off the first prize and take it to my own tent; you
+know how far my steeds excel all others--for they are immortal;
+Neptune gave them to my father Peleus, who in his turn gave them
+to myself; but I shall hold aloof, I and my steeds that have lost
+their brave and kind driver, who many a time has washed them in
+clear water and anointed their manes with oil. See how they stand
+weeping here, with their manes trailing on the ground in the
+extremity of their sorrow. But do you others set yourselves in
+order throughout the host, whosoever has confidence in his horses
+and in the strength of his chariot."
+</para>
+
+<para>
+Thus spoke the son of Peleus and the drivers of chariots
+bestirred themselves. First among them all uprose Eumelus, king
+of men, son of Admetus, a man excellent in horsemanship. Next to
+him rose mighty Diomed son of Tydeus; he yoked the Trojan horses
+which he had taken from Aeneas, when Apollo bore him out of the
+fight. Next to him, yellow-haired Menelaus son of Atreus rose and
+yoked his fleet horses, Agamemnon's mare Aethe, and his own horse
+Podargus. The mare had been given to Agamemnon by Echepolus son
+of Anchises, that he might not have to follow him to Ilius, but
+might stay at home and take his ease; for Jove had endowed him
+with great wealth and he lived in spacious Sicyon. This mare, all
+eager for the race, did Menelaus put under the yoke.
+</para>
+
+<para>
+Fourth in order Antilochus, son to noble Nestor son of Neleus,
+made ready his horses. These were bred in Pylos, and his father
+came up to him to give him good advice of which, however, he
+stood in but little need. "Antilochus," said Nestor, "you are
+young, but Jove and Neptune have loved you well, and have made
+you an excellent horseman. I need not therefore say much by way
+of instruction. You are skilful at wheeling your horses round the
+post, but the horses themselves are very slow, and it is this
+that will, I fear, mar your chances. The other drivers know less
+than you do, but their horses are fleeter; therefore, my dear
+son, see if you cannot hit upon some artifice whereby you may
+insure that the prize shall not slip through your fingers. The
+woodman does more by skill than by brute force; by skill the
+pilot guides his storm-tossed barque over the sea, and so by
+skill one driver can beat another. If a man go wide in rounding
+this way and that, whereas a man who knows what he is doing may
+have worse horses, but he will keep them well in hand when he
+sees the doubling-post; he knows the precise moment at which to
+pull the rein, and keeps his eye well on the man in front of him.
+I will give you this certain token which cannot escape your
+notice. There is a stump of a dead tree--oak or pine as it may
+be--some six feet above the ground, and not yet rotted away by
+rain; it stands at the fork of the road; it has two white stones
+set one on each side, and there is a clear course all round it.
+It may have been a monument to some one long since dead, or it
+may have been used as a doubling-post in days gone by; now,
+however, it has been fixed on by Achilles as the mark round which
+the chariots shall turn; hug it as close as you can, but as you
+stand in your chariot lean over a little to the left; urge on
+your right-hand horse with voice and lash, and give him a loose
+rein, but let the left-hand horse keep so close in, that the nave
+of your wheel shall almost graze the post; but mind the stone, or
+you will wound your horses and break your chariot in pieces,
+which would be sport for others but confusion for yourself.
+Therefore, my dear son, mind well what you are about, for if you
+can be first to round the post there is no chance of any one
+giving you the go-by later, not even though you had Adrestus's
+horse Arion behind you--a horse which is of divine race--or those
+of Laomedon, which are the noblest in this country."
+</para>
+
+<para>
+When Nestor had made an end of counselling his son he sat down in
+his place, and fifth in order Meriones got ready his horses.
+They then all mounted their chariots and cast lots. Achilles
+shook the helmet, and the lot of Antilochus son of Nestor fell
+out first; next came that of King Eumelus, and after his, those
+of Menelaus son of Atreus and of Meriones. The last place fell to
+the lot of Diomed son of Tydeus, who was the best man of them
+all. They took their places in line; Achilles showed them the
+doubling-post round which they were to turn, some way off upon
+the plain; here he stationed his father's follower Phoenix as
+umpire, to note the running, and report truly.
+</para>
+
+<para>
+At the same instant they all of them lashed their horses, struck
+them with the reins, and shouted at them with all their might.
+They flew full speed over the plain away from the ships, the dust
+rose from under them as it were a cloud or whirlwind, and their
+manes were all flying in the wind. At one moment the chariots
+seemed to touch the ground, and then again they bounded into the
+air; the drivers stood erect, and their hearts beat fast and
+furious in their lust of victory. Each kept calling on his
+horses, and the horses scoured the plain amid the clouds of dust
+that they raised.
+</para>
+
+<para>
+It was when they were doing the last part of the course on their
+way back towards the sea that their pace was strained to the
+utmost and it was seen what each could do. The horses of the
+descendant of Pheres now took the lead, and close behind them
+came the Trojan stallions of Diomed. They seemed as if about to
+mount Eumelus's chariot, and he could feel their warm breath on
+his back and on his broad shoulders, for their heads were close
+to him as they flew over the course. Diomed would have now passed
+him, or there would have been a dead heat, but Phoebus Apollo to
+spite him made him drop his whip. Tears of anger fell from his
+eyes as he saw the mares going on faster than ever, while his own
+horses lost ground through his having no whip. Minerva saw the
+trick which Apollo had played the son of Tydeus, so she brought
+him his whip and put spirit into his horses; moreover she went
+after the son of Admetus in a rage and broke his yoke for him;
+the mares went one to one side of the course, and the other to
+the other, and the pole was broken against the ground. Eumelus
+was thrown from his chariot close to the wheel; his elbows,
+mouth, and nostrils were all torn, and his forehead was bruised
+above his eyebrows; his eyes filled with tears and he could find
+no utterance. But the son of Tydeus turned his horses aside and
+shot far ahead, for Minerva put fresh strength into them and
+covered Diomed himself with glory.
+</para>
+
+<para>
+Menelaus son of Atreus came next behind him, but Antilochus
+called to his father's horses. "On with you both," he cried, "and
+do your very utmost. I do not bid you try to beat the steeds of
+the son of Tydeus, for Minerva has put running into them, and has
+covered Diomed with glory; but you must overtake the horses of
+the son of Atreus and not be left behind, or Aethe who is so
+fleet will taunt you. Why, my good fellows, are you lagging? I
+tell you, and it shall surely be--Nestor will keep neither of
+you, but will put both of you to the sword, if we win any the
+worse a prize through your carelessness. Fly after them at your
+utmost speed; I will hit on a plan for passing them in a narrow
+part of the way, and it shall not fail me."
+</para>
+
+<para>
+They feared the rebuke of their master, and for a short space
+went quicker. Presently Antilochus saw a narrow place where the
+road had sunk. The ground was broken, for the winter's rain had
+gathered and had worn the road so that the whole place was
+deepened. Menelaus was making towards it so as to get there
+first, for fear of a foul, but Antilochus turned his horses out
+of the way, and followed him a little on one side. The son of
+Atreus was afraid and shouted out, "Antilochus, you are driving
+recklessly; rein in your horses; the road is too narrow here, it
+will be wider soon, and you can pass me then; if you foul my
+chariot you may bring both of us to a mischief."
+</para>
+
+<para>
+But Antilochus plied his whip, and drove faster, as though he had
+not heard him. They went side by side for about as far as a young
+man can hurl a disc from his shoulder when he is trying his
+strength, and then Menelaus's mares drew behind, for he left off
+driving for fear the horses should foul one another and upset the
+chariots; thus, while pressing on in quest of victory, they might
+both come headlong to the ground. Menelaus then upbraided
+Antilochus and said, "There is no greater trickster living than
+you are; go, and bad luck go with you; the Achaeans say not well
+that you have understanding, and come what may you shall not bear
+away the prize without sworn protest on my part."
+</para>
+
+<para>
+Then he called on his horses and said to them, "Keep your pace,
+and slacken not; the limbs of the other horses will weary sooner
+than yours, for they are neither of them young."
+</para>
+
+<para>
+The horses feared the rebuke of their master, and went faster, so
+that they were soon nearly up with the others.
+</para>
+
+<para>
+Meanwhile the Achaeans from their seats were watching how the
+horses went, as they scoured the plain amid clouds of their own
+dust. Idomeneus captain of the Cretans was first to make out the
+running, for he was not in the thick of the crowd, but stood on
+the most commanding part of the ground. The driver was a long way
+off, but Idomeneus could hear him shouting, and could see the
+foremost horse quite plainly--a chestnut with a round white star,
+like the moon, on its forehead. He stood up and said among the
+Argives, "My friends, princes and counsellors of the Argives, can
+you see the running as well as I can? There seems to be another
+pair in front now, and another driver; those that led off at the
+start must have been disabled out on the plain. I saw them at
+first making their way round the doubling-post, but now, though I
+search the plain of Troy, I cannot find them. Perhaps the reins
+fell from the driver's hand so that he lost command of his horses
+at the doubling-post, and could not turn it. I suppose he must
+have been thrown out there, and broken his chariot, while his
+mares have left the course and gone off wildly in a panic. Come
+up and see for yourselves, I cannot make out for certain, but the
+driver seems an Aetolian by descent, ruler over the Argives,
+brave Diomed the son of Tydeus."
+</para>
+
+<para>
+Ajax the son of Oileus took him up rudely and said, "Idomeneus,
+why should you be in such a hurry to tell us all about it, when
+the mares are still so far out upon the plain? You are none of
+the youngest, nor your eyes none of the sharpest, but you are
+always laying down the law. You have no right to do so, for there
+are better men here than you are. Eumelus's horses are in front
+now, as they always have been, and he is on the chariot holding
+the reins."
+</para>
+
+<para>
+The captain of the Cretans was angry, and answered, "Ajax you are
+an excellent railer, but you have no judgement, and are wanting
+in much else as well, for you have a vile temper. I will wager
+you a tripod or cauldron, and Agamemnon son of Atreus shall
+decide whose horses are first. You will then know to your cost."
+</para>
+
+<para>
+Ajax son of Oileus was for making him an angry answer, and there
+would have been yet further brawling between them, had not
+Achilles risen in his place and said, "Cease your railing, Ajax
+and Idomeneus; is it not you would be scandalised if you saw any
+one else do the like: sit down and keep your eyes on the horses;
+they are speeding towards the winning-post and will be bere
+directly. You will then both of you know whose horses are first,
+and whose come after."
+</para>
+
+<para>
+As he was speaking, the son of Tydeus came driving in, plying his
+whip lustily from his shoulder, and his horses stepping high as
+they flew over the course. The sand and grit rained thick on the
+driver, and the chariot inlaid with gold and tin ran close behind
+his fleet horses. There was little trace of wheel-marks in the
+fine dust, and the horses came flying in at their utmost speed.
+Diomed stayed them in the middle of the crowd, and the sweat from
+their manes and chests fell in streams on to the ground.
+Forthwith he sprang from his goodly chariot, and leaned his whip
+against his horses' yoke; brave Sthenelus now lost no time, but
+at once brought on the prize, and gave the woman and the
+ear-handled cauldron to his comrades to take away. Then he
+unyoked the horses.
+</para>
+
+<para>
+Next after him came in Antilochus of the race of Neleus, who had
+passed Menelaus by a trick and not by the fleetness of his
+horses; but even so Menelaus came in as close behind him as the
+wheel is to the horse that draws both the chariot and its master.
+The end hairs of a horse's tail touch the tyre of the wheel, and
+there is never much space between wheel and horse when the
+chariot is going; Menelaus was no further than this behind
+Antilochus, though at first he had been a full disc's throw
+behind him. He had soon caught him up again, for Agamemnon's mare
+Aethe kept pulling stronger and stronger, so that if the course
+had been longer he would have passed him, and there would not
+even have been a dead heat. Idomeneus's brave squire Meriones was
+about a spear's cast behind Menelaus. His horses were slowest of
+all, and he was the worst driver. Last of them all came the son
+of Admetus, dragging his chariot and driving his horses on in
+front. When Achilles saw him he was sorry, and stood up among the
+Argives saying, "The best man is coming in last. Let us give him
+a prize for it is reasonable. He shall have the second, but the
+first must go to the son of Tydeus."
+</para>
+
+<para>
+Thus did he speak and the others all of them applauded his
+saying, and were for doing as he had said, but Nestor's son
+Antilochus stood up and claimed his rights from the son of
+Peleus. "Achilles," said he, "I shall take it much amiss if you
+do this thing; you would rob me of my prize, because you think
+Eumelus's chariot and horses were thrown out, and himself too,
+good man that he is. He should have prayed duly to the immortals;
+he would not have come in last if he had done so. If you are
+sorry for him and so choose, you have much gold in your tents,
+with bronze, sheep, cattle and horses. Take something from this
+store if you would have the Achaeans speak well of you, and give
+him a better prize even than that which you have now offered; but
+I will not give up the mare, and he that will fight me for her,
+let him come on."
+</para>
+
+<para>
+Achilles smiled as he heard this, and was pleased with
+Antilochus, who was one of his dearest comrades. So he said--
+</para>
+
+<para>
+"Antilochus, if you would have me find Eumelus another prize, I
+will give him the bronze breastplate with a rim of tin running
+all round it which I took from Asteropaeus. It will be worth much
+money to him."
+</para>
+
+<para>
+He bade his comrade Automedon bring the breastplate from his
+tent, and he did so. Achilles then gave it over to Eumelus, who
+received it gladly.
+</para>
+
+<para>
+But Menelaus got up in a rage, furiously angry with Antilochus.
+An attendant placed his staff in his hands and bade the Argives
+keep silence: the hero then addressed them. "Antilochus," said
+he, "what is this from you who have been so far blameless? You
+have made me cut a poor figure and baulked my horses by flinging
+your own in front of them, though yours are much worse than mine
+are; therefore, O princes and counsellors of the Argives, judge
+between us and show no favour, lest one of the Achaeans say,
+'Menelaus has got the mare through lying and corruption; his
+horses were far inferior to Antilochus's, but he has greater
+weight and influence.' Nay, I will determine the matter myself,
+and no man will blame me, for I shall do what is just. Come here,
+Antilochus, and stand, as our custom is, whip in hand before your
+chariot and horses; lay your hand on your steeds, and swear by
+earth-encircling Neptune that you did not purposely and
+guilefully get in the way of my horses."
+</para>
+
+<para>
+And Antilochus answered, "Forgive me; I am much younger, King
+Menelaus, than you are; you stand higher than I do and are the
+better man of the two; you know how easily young men are betrayed
+into indiscretion; their tempers are more hasty and they have
+less judgement; make due allowances therefore, and bear with me;
+I will of my own accord give up the mare that I have won, and if
+you claim any further chattel from my own possessions, I would
+rather yield it to you, at once, than fall from your good graces
+henceforth, and do wrong in the sight of heaven."
+</para>
+
+<para>
+The son of Nestor then took the mare and gave her over to
+Menelaus, whose anger was thus appeased; as when dew falls upon a
+field of ripening corn, and the lands are bristling with the
+harvest--even so, O Menelaus, was your heart made glad within
+you. He turned to Antilochus and said, "Now, Antilochus, angry
+though I have been, I can give way to you of my own free will;
+you have never been headstrong nor ill-disposed hitherto, but
+this time your youth has got the better of your judgement; be
+careful how you outwit your betters in future; no one else could
+have brought me round so easily, but your good father, your
+brother, and yourself have all of you had infinite trouble on my
+behalf; I therefore yield to your entreaty, and will give up the
+mare to you, mine though it indeed be; the people will thus see
+that I am neither harsh nor vindictive."
+</para>
+
+<para>
+With this he gave the mare over to Antilochus's comrade Noemon,
+and then took the cauldron. Meriones, who had come in fourth,
+carried off the two talents of gold, and the fifth prize, the
+two-handled urn, being unawarded, Achilles gave it to Nestor,
+going up to him among the assembled Argives and saying, "Take
+this, my good old friend, as an heirloom and memorial of the
+funeral of Patroclus--for you shall see him no more among the
+Argives. I give you this prize though you cannot win one; you can
+now neither wrestle nor fight, and cannot enter for the
+javelin-match nor foot-races, for the hand of age has been laid
+heavily upon you."
+</para>
+
+<para>
+So saying he gave the urn over to Nestor, who received it gladly
+and answered, "My son, all that you have said is true; there is
+no strength now in my legs and feet, nor can I hit out with my
+hands from either shoulder. Would that I were still young and
+strong as when the Epeans were burying King Amarynceus in
+Buprasium, and his sons offered prizes in his honour. There was
+then none that could vie with me neither of the Epeans nor the
+Pylians themselves nor the Aetolians. In boxing I overcame
+Clytomedes son of Enops, and in wrestling, Ancaeus of Pleuron who
+had come forward against me. Iphiclus was a good runner, but I
+beat him, and threw farther with my spear than either Phyleus or
+Polydorus. In chariot-racing alone did the two sons of Actor
+surpass me by crowding their horses in front of me, for they were
+angry at the way victory had gone, and at the greater part of the
+prizes remaining in the place in which they had been offered.
+They were twins, and the one kept on holding the reins, and
+holding the reins, while the other plied the whip. Such was I
+then, but now I must leave these matters to younger men; I must
+bow before the weight of years, but in those days I was eminent
+among heroes. And now, sir, go on with the funeral contests in
+honour of your comrade: gladly do I accept this urn, and my heart
+rejoices that you do not forget me but are ever mindful of my
+goodwill towards you, and of the respect due to me from the
+Achaeans. For all which may the grace of heaven be vouchsafed you
+in great abundance."
+</para>
+
+<para>
+Thereon the son of Peleus, when he had listened to all the thanks
+of Nestor, went about among the concourse of the Achaeans, and
+presently offered prizes for skill in the painful art of boxing.
+He brought out a strong mule, and made it fast in the middle of
+the crowd--a she-mule never yet broken, but six years old--when
+it is hardest of all to break them: this was for the victor, and
+for the vanquished he offered a double cup. Then he stood up and
+said among the Argives, "Son of Atreus, and all other Achaeans, I
+invite our two champion boxers to lay about them lustily and
+compete for these prizes. He to whom Apollo vouchsafes the
+greater endurance, and whom the Achaeans acknowledge as victor,
+shall take the mule back with him to his own tent, while he that
+is vanquished shall have the double cup."
+</para>
+
+<para>
+As he spoke there stood up a champion both brave and great
+stature, a skilful boxer, Epeus, son of Panopeus. He laid his
+hand on the mule and said, "Let the man who is to have the cup
+come hither, for none but myself will take the mule. I am the
+best boxer of all here present, and none can beat me. Is it not
+enough that I should fall short of you in actual fighting? Still,
+no man can be good at everything. I tell you plainly, and it
+shall come true; if any man will box with me I will bruise his
+body and break his bones; therefore let his friends stay here in
+a body and be at hand to take him away when I have done with
+him."
+</para>
+
+<para>
+They all held their peace, and no man rose save Euryalus son of
+Mecisteus, who was son of Talaus. Mecisteus went once to Thebes
+after the fall of Oedipus, to attend his funeral, and he beat all
+the people of Cadmus. The son of Tydeus was Euryalus's second,
+cheering him on and hoping heartily that he would win. First he
+put a waistband round him and then he gave him some well-cut
+thongs of ox-hide; the two men being now girt went into the
+middle of the ring, and immediately fell to; heavily indeed did
+they punish one another and lay about them with their brawny
+fists. One could hear the horrid crashing of their jaws, and they
+sweated from every pore of their skin. Presently Epeus came on
+and gave Euryalus a blow on the jaw as he was looking round;
+Euryalus could not keep his legs; they gave way under him in a
+moment and he sprang up with a bound, as a fish leaps into the
+air near some shore that is all bestrewn with sea-wrack, when
+Boreas furs the top of the waves, and then falls back into deep
+water. But noble Epeus caught hold of him and raised him up; his
+comrades also came round him and led him from the ring, unsteady
+in his gait, his head hanging on one side, and spitting great
+clots of gore. They set him down in a swoon and then went to
+fetch the double cup.
+</para>
+
+<para>
+The son of Peleus now brought out the prizes for the third
+contest and showed them to the Argives. These were for the
+painful art of wrestling. For the winner there was a great tripod
+ready for setting upon the fire, and the Achaeans valued it among
+themselves at twelve oxen. For the loser he brought out a woman
+skilled in all manner of arts, and they valued her at four oxen.
+He rose and said among the Argives, "Stand forward, you who will
+essay this contest."
+</para>
+
+<para>
+Forthwith uprose great Ajax the son of Telamon, and crafty
+Ulysses, full of wiles, rose also. The two girded themselves and
+went into the middle of the ring. They gripped each other in
+their strong hands like the rafters which some master-builder
+frames for the roof of a high house to keep the wind out. Their
+backbones cracked as they tugged at one another with their mighty
+arms--and sweat rained from them in torrents. Many a bloody weal
+sprang up on their sides and shoulders, but they kept on striving
+with might and main for victory and to win the tripod. Ulysses
+could not throw Ajax, nor Ajax him; Ulysses was too strong for
+him; but when the Achaeans began to tire of watching them, Ajax
+said to Ulysses, "Ulysses, noble son of Laertes, you shall either
+lift me, or I you, and let Jove settle it between us."
+</para>
+
+<para>
+He lifted him from the ground as he spoke, but Ulysses did not
+forget his cunning. He hit Ajax in the hollow at back of his
+knee, so that he could not keep his feet, but fell on his back
+with Ulysses lying upon his chest, and all who saw it marvelled.
+Then Ulysses in turn lifted Ajax and stirred him a little from
+the ground but could not lift him right off it, his knee sank
+under him, and the two fell side by side on the ground and were
+all begrimed with dust. They now sprang towards one another and
+were for wrestling yet a third time, but Achilles rose and stayed
+them. "Put not each other further," said he, "to such cruel
+suffering; the victory is with both alike, take each of you an
+equal prize, and let the other Achaeans now compete."
+</para>
+
+<para>
+Thus did he speak and they did even as he had said, and put on
+their shirts again after wiping the dust from off their bodies.
+</para>
+
+<para>
+The son of Peleus then offered prizes for speed in running--a
+mixing-bowl beautifully wrought, of pure silver. It would hold
+six measures, and far exceeded all others in the whole world for
+beauty; it was the work of cunning artificers in Sidon, and had
+been brought into port by Phoenicians from beyond the sea, who
+had made a present of it to Thoas. Eueneus son of Jason had given
+it to Patroclus in ransom of Priam's son Lycaon, and Achilles now
+offered it as a prize in honour of his comrade to him who should
+be the swiftest runner. For the second prize he offered a large
+ox, well fattened, while for the last there was to be half a
+talent of gold. He then rose and said among the Argives, "Stand
+forward, you who will essay this contest."
+</para>
+
+<para>
+Forthwith uprose fleet Ajax son of Oileus, with cunning Ulysses,
+and Nestor's son Antilochus, the fastest runner among all the
+youth of his time. They stood side by side and Achilles showed
+them the goal. The course was set out for them from the
+starting-post, and the son of Oileus took the lead at once, with
+Ulysses as close behind him as the shuttle is to a woman's bosom
+when she throws the woof across the warp and holds it close up to
+her; even so close behind him was Ulysses--treading in his
+footprints before the dust could settle there, and Ajax could
+feel his breath on the back of his head as he ran swiftly on. The
+Achaeans all shouted applause as they saw him straining his
+utmost, and cheered him as he shot past them; but when they were
+now nearing the end of the course Ulysses prayed inwardly to
+Minerva. "Hear me," he cried, "and help my feet, O goddess." Thus
+did he pray, and Pallas Minerva heard his prayer; she made his
+hands and his feet feel light, and when the runners were at the
+point of pouncing upon the prize, Ajax, through Minerva's spite
+slipped upon some offal that was lying there from the cattle
+which Achilles had slaughtered in honour of Patroclus, and his
+mouth and nostrils were all filled with cow dung. Ulysses
+therefore carried off the mixing-bowl, for he got before Ajax and
+came in first. But Ajax took the ox and stood with his hand on
+one of its horns, spitting the dung out of his mouth. Then he
+said to the Argives, "Alas, the goddess has spoiled my running;
+she watches over Ulysses and stands by him as though she were his
+own mother." Thus did he speak and they all of them laughed
+heartily.
+</para>
+
+<para>
+Antilochus carried off the last prize and smiled as he said to
+the bystanders, "You all see, my friends, that now too the gods
+have shown their respect for seniority. Ajax is somewhat older
+than I am, and as for Ulysses, he belongs to an earlier
+generation, but he is hale in spite of his years, and no man of
+the Achaeans can run against him save only Achilles."
+</para>
+
+<para>
+He said this to pay a compliment to the son of Peleus, and
+Achilles answered, "Antilochus, you shall not have praised me to
+no purpose; I shall give you an additional half talent of gold."
+He then gave the half talent to Antilochus, who received it
+gladly.
+</para>
+
+<para>
+Then the son of Peleus brought out the spear, helmet and shield
+that had been borne by Sarpedon, and were taken from him by
+Patroclus. He stood up and said among the Argives, "We bid two
+champions put on their armour, take their keen blades, and make
+trial of one another in the presence of the multitude; whichever
+of them can first wound the flesh of the other, cut through his
+armour, and draw blood, to him will I give this goodly Thracian
+sword inlaid with silver, which I took from Asteropaeus, but the
+armour let both hold in partnership, and I will give each of them
+a hearty meal in my own tent."
+</para>
+
+<para>
+Forthwith uprose great Ajax the son of Telamon, as also mighty
+Diomed son of Tydeus. When they had put on their armour each on
+his own side of the ring, they both went into the middle eager to
+engage, and with fire flashing from their eyes. The Achaeans
+marvelled as they beheld them, and when the two were now close up
+with one another, thrice did they spring forward and thrice try
+to strike each other in close combat. Ajax pierced Diomed's round
+shield, but did not draw blood, for the cuirass beneath the
+shield protected him; thereon the son of Tydeus from over his
+huge shield kept aiming continually at Ajax's neck with the point
+of his spear, and the Achaeans alarmed for his safety bade them
+leave off fighting and divide the prize between them. Achilles
+then gave the great sword to the son of Tydeus, with its
+scabbard, and the leathern belt with which to hang it.
+</para>
+
+<para>
+Achilles next offered the massive iron quoit which mighty Eetion
+had erewhile been used to hurl, until Achilles had slain him and
+carried it off in his ships along with other spoils. He stood up
+and said among the Argives, "Stand forward, you who would essay
+this contest. He who wins it will have a store of iron that will
+last him five years as they go rolling round, and if his fair
+fields lie far from a town his shepherd or ploughman will not
+have to make a journey to buy iron, for he will have a stock of
+it on his own premises."
+</para>
+
+<para>
+Then uprose the two mighty men Polypoetes and Leonteus, with Ajax
+son of Telamon and noble Epeus. They stood up one after the other
+and Epeus took the quoit, whirled it, and flung it from him,
+which set all the Achaeans laughing. After him threw Leonteus of
+the race of Mars. Ajax son of Telamon threw third, and sent the
+quoit beyond any mark that had been made yet, but when mighty
+Polypoetes took the quoit he hurled it as though it had been a
+stockman's stick which he sends flying about among his cattle
+when he is driving them, so far did his throw out-distance those
+of the others. All who saw it roared applause, and his comrades
+carried the prize for him and set it on board his ship.
+</para>
+
+<para>
+Achilles next offered a prize of iron for archery--ten
+double-edged axes and ten with single edges: he set up a ship's
+mast, some way off upon the sands, and with a fine string tied a
+pigeon to it by the foot; this was what they were to aim at.
+"Whoever," he said, "can hit the pigeon shall have all the axes
+and take them away with him; he who hits the string without
+hitting the bird will have taken a worse aim and shall have the
+single-edged axes."
+</para>
+
+<para>
+Then uprose King Teucer, and Meriones the stalwart squire of
+Idomeneus rose also, They cast lots in a bronze helmet and the
+lot of Teucer fell first. He let fly with his arrow forthwith,
+but he did not promise hecatombs of firstling lambs to King
+Apollo, and missed his bird, for Apollo foiled his aim; but he
+hit the string with which the bird was tied, near its foot; the
+arrow cut the string clean through so that it hung down towards
+the ground, while the bird flew up into the sky, and the Achaeans
+shouted applause. Meriones, who had his arrow ready while Teucer
+was aiming, snatched the bow out of his hand, and at once
+promised that he would sacrifice a hecatomb of firstling lambs to
+Apollo lord of the bow; then espying the pigeon high up under the
+clouds, he hit her in the middle of the wing as she was circling
+upwards; the arrow went clean through the wing and fixed itself
+in the ground at Meriones' feet, but the bird perched on the
+ship's mast hanging her head and with all her feathers drooping;
+the life went out of her, and she fell heavily from the mast.
+Meriones, therefore, took all ten double-edged axes, while Teucer
+bore off the single-edged ones to his ships.
+</para>
+
+<para>
+Then the son of Peleus brought in a spear and a cauldron that had
+never been on the fire; it was worth an ox, and was chased with a
+pattern of flowers; and those that throw the javelin stood up--to
+wit the son of Atreus, king of men Agamemnon, and Meriones,
+stalwart squire of Idomeneus. But Achilles spoke saying, "Son of
+Atreus, we know how far you excel all others both in power and in
+throwing the javelin; take the cauldron back with you to your
+ships, but if it so please you, let us give the spear to
+Meriones; this at least is what I should myself wish."
+</para>
+
+<para>
+King Agamemnon assented. So he gave the bronze spear to Meriones,
+and handed the goodly cauldron to Talthybius his esquire.
+</para>
+</chapter>
+
+<chapter>
+<title>BOOK XXIV</title>
+
+<para>
+THE assembly now broke up and the people went their ways each to
+his own ship. There they made ready their supper, and then
+bethought them of the blessed boon of sleep; but Achilles still
+wept for thinking of his dear comrade, and sleep, before whom all
+things bow, could take no hold upon him. This way and that did he
+turn as he yearned after the might and manfulness of Patroclus;
+he thought of all they had done together, and all they had gone
+through both on the field of battle and on the waves of the weary
+sea. As he dwelt on these things he wept bitterly and lay now on
+his side, now on his back, and now face downwards, till at last
+he rose and went out as one distraught to wander upon the
+seashore. Then, when he saw dawn breaking over beach and sea, he
+yoked his horses to his chariot, and bound the body of Hector
+behind it that he might drag it about. Thrice did he drag it
+round the tomb of the son of Menoetius, and then went back into
+his tent, leaving the body on the ground full length and with its
+face downwards. But Apollo would not suffer it to be disfigured,
+for he pitied the man, dead though he now was; therefore he
+shielded him with his golden aegis continually, that he might
+take no hurt while Achilles was dragging him.
+</para>
+
+<para>
+Thus shamefully did Achilles in his fury dishonour Hector; but
+the blessed gods looked down in pity from heaven, and urged
+Mercury, slayer of Argus, to steal the body. All were of this
+mind save only Juno, Neptune, and Jove's grey-eyed daughter, who
+persisted in the hate which they had ever borne towards Ilius
+with Priam and his people; for they forgave not the wrong done
+them by Alexandrus in disdaining the goddesses who came to him
+when he was in his sheepyards, and preferring her who had offered
+him a wanton to his ruin.
+</para>
+
+<para>
+When, therefore, the morning of the twelfth day had now come,
+Phoebus Apollo spoke among the immortals saying, "You gods ought
+to be ashamed of yourselves; you are cruel and hard-hearted. Did
+not Hector burn you thigh-bones of heifers and of unblemished
+goats? And now dare you not rescue even his dead body, for his
+wife to look upon, with his mother and child, his father Priam,
+and his people, who would forthwith commit him to the flames, and
+give him his due funeral rites? So, then, you would all be on the
+side of mad Achilles, who knows neither right nor ruth? He is
+like some savage lion that in the pride of his great strength and
+daring springs upon men's flocks and gorges on them. Even so has
+Achilles flung aside all pity, and all that conscience which at
+once so greatly banes yet greatly boons him that will heed it.
+man may lose one far dearer than Achilles has lost--a son, it may
+be, or a brother born from his own mother's womb; yet when he has
+mourned him and wept over him he will let him bide, for it takes
+much sorrow to kill a man; whereas Achilles, now that he has
+slain noble Hector, drags him behind his chariot round the tomb
+of his comrade. It were better of him, and for him, that he
+should not do so, for brave though he be we gods may take it ill
+that he should vent his fury upon dead clay."
+</para>
+
+<para>
+Juno spoke up in a rage. "This were well," she cried, "O lord of
+the silver bow, if you would give like honour to Hector and to
+Achilles; but Hector was mortal and suckled at a woman's breast,
+whereas Achilles is the offspring of a goddess whom I myself
+reared and brought up. I married her to Peleus, who is above
+measure dear to the immortals; you gods came all of you to her
+wedding; you feasted along with them yourself and brought your
+lyre--false, and fond of low company, that you have ever been."
+</para>
+
+<para>
+Then said Jove, "Juno, be not so bitter. Their honour shall not
+be equal, but of all that dwell in Ilius, Hector was dearest to
+the gods, as also to myself, for his offerings never failed me.
+Never was my altar stinted of its dues, nor of the
+drink-offerings and savour of sacrifice which we claim of right.
+I shall therefore permit the body of mighty Hector to be stolen;
+and yet this may hardly be without Achilles coming to know it,
+for his mother keeps night and day beside him. Let some one of
+you, therefore, send Thetis to me, and I will impart my counsel
+to her, namely that Achilles is to accept a ransom from Priam,
+and give up the body."
+</para>
+
+<para>
+On this Iris fleet as the wind went forth to carry his message.
+Down she plunged into the dark sea midway between Samos and rocky
+Imbrus; the waters hissed as they closed over her, and she sank
+into the bottom as the lead at the end of an ox-horn, that is
+sped to carry death to fishes. She found Thetis sitting in a
+great cave with the other sea-goddesses gathered round her; there
+she sat in the midst of them weeping for her noble son who was to
+fall far from his own land, on the rich plains of Troy. Iris went
+up to her and said, "Rise Thetis; Jove, whose counsels fail not,
+bids you come to him." And Thetis answered, "Why does the mighty
+god so bid me? I am in great grief, and shrink from going in and
+out among the immortals. Still, I will go, and the word that he
+may speak shall not be spoken in vain."
+</para>
+
+<para>
+The goddess took her dark veil, than which there can be no robe
+more sombre, and went forth with fleet Iris leading the way
+before her. The waves of the sea opened them a path, and when
+they reached the shore they flew up into the heavens, where they
+found the all-seeing son of Saturn with the blessed gods that
+live for ever assembled near him. Minerva gave up her seat to
+her, and she sat down by the side of father Jove. Juno then
+placed a fair golden cup in her hand, and spoke to her in words
+of comfort, whereon Thetis drank and gave her back the cup; and
+the sire of gods and men was the first to speak.
+</para>
+
+<para>
+"So, goddess," said he, "for all your sorrow, and the grief that
+I well know reigns ever in your heart, you have come hither to
+Olympus, and I will tell you why I have sent for you. This nine
+days past the immortals have been quarrelling about Achilles
+waster of cities and the body of Hector. The gods would have
+Mercury slayer of Argus steal the body, but in furtherance of our
+peace and amity henceforward, I will concede such honour to your
+son as I will now tell you. Go, then, to the host and lay these
+commands upon him; say that the gods are angry with him, and that
+I am myself more angry than them all, in that he keeps Hector at
+the ships and will not give him up. He may thus fear me and let
+the body go. At the same time I will send Iris to great Priam to
+bid him go to the ships of the Achaeans, and ransom his son,
+taking with him such gifts for Achilles as may give him
+satisfaction."
+</para>
+
+<para>
+Silver-footed Thetis did as the god had told her, and forthwith
+down she darted from the topmost summits of Olympus. She went to
+her son's tents where she found him grieving bitterly, while his
+trusty comrades round him were busy preparing their morning meal,
+for which they had killed a great woolly sheep. His mother sat
+down beside him and caressed him with her hand saying, "My son,
+how long will you keep on thus grieving and making moan? You are
+gnawing at your own heart, and think neither of food nor of
+woman's embraces; and yet these too were well, for you have no
+long time to live, and death with the strong hand of fate are
+already close beside you. Now, therefore, heed what I say, for I
+come as a messenger from Jove; he says that the gods are angry
+with you, and himself more angry than them all, in that you keep
+Hector at the ships and will not give him up. Therefore let him
+go, and accept a ransom for his body."
+</para>
+
+<para>
+And Achilles answered, "So be it. If Olympian Jove of his own
+motion thus commands me, let him that brings the ransom bear the
+body away."
+</para>
+
+<para>
+Thus did mother and son talk together at the ships in long
+discourse with one another. Meanwhile the son of Saturn sent Iris
+to the strong city of Ilius. "Go," said he, "fleet Iris, from the
+mansions of Olympus, and tell King Priam in Ilius, that he is to
+go to the ships of the Achaeans and free the body of his dear
+son. He is to take such gifts with him as shall give satisfaction
+to Achilles, and he is to go alone, with no other Trojan, save
+only some honoured servant who may drive his mules and waggon,
+and bring back the body of him whom noble Achilles has slain. Let
+him have no thought nor fear of death in his heart, for we will
+send the slayer of Argus to escort him, and bring him within the
+tent of Achilles. Achilles will not kill him nor let another do
+so, for he will take heed to his ways and sin not, and he will
+entreat a suppliant with all honourable courtesy."
+</para>
+
+<para>
+On this Iris, fleet as the wind, sped forth to deliver her
+message. She went to Priam's house, and found weeping and
+lamentation therein. His sons were seated round their father in
+the outer courtyard, and their raiment was wet with tears: the
+old man sat in the midst of them with his mantle wrapped close
+about his body, and his head and neck all covered with the filth
+which he had clutched as he lay grovelling in the mire. His
+daughters and his sons' wives went wailing about the house, as
+they thought of the many and brave men who lay dead, slain by the
+Argives. The messenger of Jove stood by Priam and spoke softly to
+him, but fear fell upon him as she did so. "Take heart," she
+said, "Priam offspring of Dardanus, take heart and fear not. I
+bring no evil tidings, but am minded well towards you. I come as
+a messenger from Jove, who though he be not near, takes thought
+for you and pities you. The lord of Olympus bids you go and
+ransom noble Hector, and take with you such gifts as shall give
+satisfaction to Achilles. You are to go alone, with no Trojan,
+save only some honoured servant who may drive your mules and
+waggon, and bring back to the city the body of him whom noble
+Achilles has slain. You are to have no thought, nor fear of
+death, for Jove will send the slayer of Argus to escort you. When
+he has brought you within Achilles' tent, Achilles will not kill
+you nor let another do so, for he will take heed to his ways and
+sin not, and he will entreat a suppliant with all honourable
+courtesy."
+</para>
+
+<para>
+Iris went her way when she had thus spoken, and Priam told his
+sons to get a mule-waggon ready, and to make the body of the
+waggon fast upon the top of its bed. Then he went down into his
+fragrant store-room, high-vaulted, and made of cedar-wood, where
+his many treasures were kept, and he called Hecuba his wife.
+"Wife," said he, "a messenger has come to me from Olympus, and
+has told me to go to the ships of the Achaeans to ransom my dear
+son, taking with me such gifts as shall give satisfaction to
+Achilles. What think you of this matter? for my own part I am
+greatly moved to pass through the camps of the Achaeans and go to
+their ships."
+</para>
+
+<para>
+His wife cried aloud as she heard him, and said, "Alas, what has
+become of that judgement for which you have been ever famous both
+among strangers and your own people? How can you venture alone to
+the ships of the Achaeans, and look into the face of him who has
+slain so many of your brave sons? You must have iron courage, for
+if the cruel savage sees you and lays hold on you, he will know
+neither respect nor pity. Let us then weep Hector from afar here
+in our own house, for when I gave him birth the threads of
+overruling fate were spun for him that dogs should eat his flesh
+far from his parents, in the house of that terrible man on whose
+liver I would fain fasten and devour it. Thus would I avenge my
+son, who showed no cowardice when Achilles slew him, and thought
+neither of flight nor of avoiding battle as he stood in defence
+of Trojan men and Trojan women."
+</para>
+
+<para>
+Then Priam said, "I would go, do not therefore stay me nor be as
+a bird of ill omen in my house, for you will not move me. Had it
+been some mortal man who had sent me some prophet or priest who
+divines from sacrifice--I should have deemed him false and have
+given him no heed; but now I have heard the goddess and seen her
+face to face, therefore I will go and her saying shall not be in
+vain. If it be my fate to die at the ships of the Achaeans even
+so would I have it; let Achilles slay me, if I may but first have
+taken my son in my arms and mourned him to my heart's
+comforting."
+</para>
+
+<para>
+So saying he lifted the lids of his chests, and took out twelve
+goodly vestments. He took also twelve cloaks of single fold,
+twelve rugs, twelve fair mantles, and an equal number of shirts.
+He weighed out ten talents of gold, and brought moreover two
+burnished tripods, four cauldrons, and a very beautiful cup which
+the Thracians had given him when he had gone to them on an
+embassy; it was very precious, but he grudged not even this, so
+eager was he to ransom the body of his son. Then he chased all
+the Trojans from the court and rebuked them with words of anger.
+"Out," he cried, "shame and disgrace to me that you are. Have you
+no grief in your own homes that you are come to plague me here?
+Is it a small thing, think you, that the son of Saturn has sent
+this sorrow upon me, to lose the bravest of my sons? Nay, you
+shall prove it in person, for now he is gone the Achaeans will
+have easier work in killing you. As for me, let me go down within
+the house of Hades, ere mine eyes behold the sacking and wasting
+of the city."
+</para>
+
+<para>
+He drove the men away with his staff, and they went forth as the
+old man sped them. Then he called to his sons, upbraiding
+Helenus, Paris, noble Agathon, Pammon, Antiphonus, Polites of the
+loud battle-cry, Deiphobus, Hippothous, and Dius. These nine did
+the old man call near him. "Come to me at once," he cried,
+"worthless sons who do me shame; would that you had all been
+killed at the ships rather than Hector. Miserable man that I am,
+I have had the bravest sons in all Troy--noble Nestor, Troilus
+the dauntless charioteer, and Hector who was a god among men, so
+that one would have thought he was son to an immortal--yet there
+is not one of them left. Mars has slain them and those of whom I
+am ashamed are alone left me. Liars, and light of foot, heroes of
+the dance, robbers of lambs and kids from your own people, why do
+you not get a waggon ready for me at once, and put all these
+things upon it that I may set out on my way?"
+</para>
+
+<para>
+Thus did he speak, and they feared the rebuke of their father.
+They brought out a strong mule-waggon, newly made, and set the
+body of the waggon fast on its bed. They took the mule-yoke from
+the peg on which it hung, a yoke of boxwood with a knob on the
+top of it and rings for the reins to go through. Then they
+brought a yoke-band eleven cubits long, to bind the yoke to the
+pole; they bound it on at the far end of the pole, and put the
+ring over the upright pin making it fast with three turns of the
+band on either side the knob, and bending the thong of the yoke
+beneath it. This done, they brought from the store-chamber the
+rich ransom that was to purchase the body of Hector, and they set
+it all orderly on the waggon; then they yoked the strong
+harness-mules which the Mysians had on a time given as a goodly
+present to Priam; but for Priam himself they yoked horses which
+the old king had bred, and kept for own use.
+</para>
+
+<para>
+Thus heedfully did Priam and his servant see to the yolking of
+their cars at the palace. Then Hecuba came to them all sorrowful,
+with a golden goblet of wine in her right hand, that they might
+make a drink-offering before they set out. She stood in front of
+the horses and said, "Take this, make a drink-offering to father
+Jove, and since you are minded to go to the ships in spite of me,
+pray that you may come safely back from the hands of your
+enemies. Pray to the son of Saturn lord of the whirlwind, who
+sits on Ida and looks down over all Troy, pray him to send his
+swift messenger on your right hand, the bird of omen which is
+strongest and most dear to him of all birds, that you may see it
+with your own eyes and trust it as you go forth to the ships of
+the Danaans. If all-seeing Jove will not send you this messenger,
+however set upon it you may be, I would not have you go to the
+ships of the Argives."
+</para>
+
+<para>
+And Priam answered, "Wife, I will do as you desire me; it is well
+to lift hands in prayer to Jove, if so be he may have mercy upon
+me."
+</para>
+
+<para>
+With this the old man bade the serving-woman pour pure water over
+his hands, and the woman came, bearing the water in a bowl. He
+washed his hands and took the cup from his wife; then he made the
+drink-offering and prayed, standing in the middle of the
+courtyard and turning his eyes to heaven. "Father Jove," he said,
+"that rulest from Ida, most glorious and most great, grant that I
+may be received kindly and compassionately in the tents of
+Achilles; and send your swift messenger upon my right hand, the
+bird of omen which is strongest and most dear to you of all
+birds, that I may see it with my own eyes and trust it as I go
+forth to the ships of the Danaans."
+</para>
+
+<para>
+So did he pray, and Jove the lord of counsel heard his prayer.
+Forthwith he sent an eagle, the most unerring portent of all
+birds that fly, the dusky hunter that men also call the Black
+Eagle. His wings were spread abroad on either side as wide as the
+well-made and well-bolted door of a rich man's chamber. He came
+to them flying over the city upon their right hands, and when
+they saw him they were glad and their hearts took comfort within
+them. The old man made haste to mount his chariot, and drove out
+through the inner gateway and under the echoing gatehouse of the
+outer court. Before him went the mules drawing the four-wheeled
+waggon, and driven by wise Idaeus; behind these were the horses,
+which the old man lashed with his whip and drove swiftly through
+the city, while his friends followed after, wailing and lamenting
+for him as though he were on his road to death. As soon as they
+had come down from the city and had reached the plain, his sons
+and sons-in-law who had followed him went back to Ilius.
+</para>
+
+<para>
+But Priam and Idaeus as they showed out upon the plain did not
+escape the ken of all-seeing Jove, who looked down upon the old
+man and pitied him; then he spoke to his son Mercury and said,
+"Mercury, for it is you who are the most disposed to escort men
+on their way, and to hear those whom you will hear, go, and so
+conduct Priam to the ships of the Achaeans that no other of the
+Danaans shall see him nor take note of him until he reach the son
+of Peleus."
+</para>
+
+<para>
+Thus he spoke and Mercury, guide and guardian, slayer of Argus,
+did as he was told. Forthwith he bound on his glittering golden
+sandals with which he could fly like the wind over land and sea;
+he took the wand with which he seals men's eyes in sleep, or
+wakes them just as he pleases, and flew holding it in his hand
+till he came to Troy and to the Hellespont. To look at, he was
+like a young man of noble birth in the hey-day of his youth and
+beauty with the down just coming upon his face.
+</para>
+
+<para>
+Now when Priam and Idaeus had driven past the great tomb of
+Ilius, they stayed their mules and horses that they might drink
+in the river, for the shades of night were falling, when,
+therefore, Idaeus saw Mercury standing near them he said to
+Priam, "Take heed, descendant of Dardanus; here is matter which
+demands consideration. I see a man who I think will presently
+fall upon us; let us fly with our horses, or at least embrace his
+knees and implore him to take compassion upon us?"
+</para>
+
+<para>
+When he heard this the old man's heart failed him, and he was in
+great fear; he stayed where he was as one dazed, and the hair
+stood on end over his whole body; but the bringer of good luck
+came up to him and took him by the hand, saying, "Whither,
+father, are you thus driving your mules and horses in the dead of
+night when other men are asleep? Are you not afraid of the fierce
+Achaeans who are hard by you, so cruel and relentless? Should
+some one of them see you bearing so much treasure through the
+darkness of the flying night, what would not your state then be?
+You are no longer young, and he who is with you is too old to
+protect you from those who would attack you. For myself, I will
+do you no harm, and I will defend you from any one else, for you
+remind me of my own father."
+</para>
+
+<para>
+And Priam answered, "It is indeed as you say, my dear son;
+nevertheless some god has held his hand over me, in that he has
+sent such a wayfarer as yourself to meet me so opportunely; you
+are so comely in mien and figure, and your judgement is so
+excellent that you must come of blessed parents."
+</para>
+
+<para>
+Then said the slayer of Argus, guide and guardian, "Sir, all that
+you have said is right; but tell me and tell me true, are you
+taking this rich treasure to send it to a foreign people where it
+may be safe, or are you all leaving strong Ilius in dismay now
+that your son has fallen who was the bravest man among you and
+was never lacking in battle with the Achaeans?"
+</para>
+
+<para>
+And Priam said, "Who are you, my friend, and who are your
+parents, that you speak so truly about the fate of my unhappy
+son?"
+</para>
+
+<para>
+The slayer of Argus, guide and guardian, answered him, "Sir, you
+would prove me, that you question me about noble Hector. Many a
+time have I set eyes upon him in battle when he was driving the
+Argives to their ships and putting them to the sword. We stood
+still and marvelled, for Achilles in his anger with the son of
+Atreus suffered us not to fight. I am his squire, and came with
+him in the same ship. I am a Myrmidon, and my father's name is
+Polyctor: he is a rich man and about as old as you are; he has
+six sons besides myself, and I am the seventh. We cast lots, and
+it fell upon me to sail hither with Achilles. I am now come from
+the ships on to the plain, for with daybreak the Achaeans will
+set battle in array about the city. They chafe at doing nothing,
+and are so eager that their princes cannot hold them back."
+</para>
+
+<para>
+Then answered Priam, "If you are indeed the squire of Achilles
+son of Peleus, tell me now the whole truth. Is my son still at
+the ships, or has Achilles hewn him limb from limb, and given him
+to his hounds?"
+</para>
+
+<para>
+"Sir," replied the slayer of Argus, guide and guardian, "neither
+hounds nor vultures have yet devoured him; he is still just lying
+at the tents by the ship of Achilles, and though it is now twelve
+days that he has lain there, his flesh is not wasted nor have the
+worms eaten him although they feed on warriors. At daybreak
+Achilles drags him cruelly round the sepulchre of his dear
+comrade, but it does him no hurt. You should come yourself and
+see how he lies fresh as dew, with the blood all washed away, and
+his wounds every one of them closed though many pierced him with
+their spears. Such care have the blessed gods taken of your brave
+son, for he was dear to them beyond all measure."
+</para>
+
+<para>
+The old man was comforted as he heard him and said, "My son, see
+what a good thing it is to have made due offerings to the
+immortals; for as sure as that he was born my son never forgot
+the gods that hold Olympus, and now they requite it to him even
+in death. Accept therefore at my hands this goodly chalice; guard
+me and with heaven's help guide me till I come to the tent of the
+son of Peleus."
+</para>
+
+<para>
+Then answered the slayer of Argus, guide and guardian, "Sir, you
+are tempting me and playing upon my youth, but you shall not move
+me, for you are offering me presents without the knowledge of
+Achilles whom I fear and hold it great guilt to defraud, lest
+some evil presently befall me; but as your guide I would go with
+you even to Argos itself, and would guard you so carefully
+whether by sea or land, that no one should attack you through
+making light of him who was with you."
+</para>
+
+<para>
+The bringer of good luck then sprang on to the chariot, and
+seizing the whip and reins he breathed fresh spirit into the
+mules and horses. When they reached the trench and the wall that
+was before the ships, those who were on guard had just been
+getting their suppers, and the slayer of Argus threw them all
+into a deep sleep. Then he drew back the bolts to open the gates,
+and took Priam inside with the treasure he had upon his waggon.
+Ere long they came to the lofty dwelling of the son of Peleus for
+which the Myrmidons had cut pine and which they had built for
+their king; when they had built it they thatched it with coarse
+tussock-grass which they had mown out on the plain, and all round
+it they made a large courtyard, which was fenced with stakes set
+close together. The gate was barred with a single bolt of pine
+which it took three men to force into its place, and three to
+draw back so as to open the gate, but Achilles could draw it by
+himself. Mercury opened the gate for the old man, and brought in
+the treasure that he was taking with him for the son of Peleus.
+Then he sprang from the chariot on to the ground and said, "Sir,
+it is I, immortal Mercury, that am come with you, for my father
+sent me to escort you. I will now leave you, and will not enter
+into the presence of Achilles, for it might anger him that a god
+should befriend mortal men thus openly. Go you within, and
+embrace the knees of the son of Peleus: beseech him by his
+father, his lovely mother, and his son; thus you may move him."
+</para>
+
+<para>
+With these words Mercury went back to high Olympus. Priam sprang
+from his chariot to the ground, leaving Idaeus where he was, in
+charge of the mules and horses. The old man went straight into
+the house where Achilles, loved of the gods, was sitting. There
+he found him with his men seated at a distance from him: only
+two, the hero Automedon, and Alcimus of the race of Mars, were
+busy in attendance about his person, for he had but just done
+eating and drinking, and the table was still there. King Priam
+entered without their seeing him, and going right up to Achilles
+he clasped his knees and kissed the dread murderous hands that
+had slain so many of his sons.
+</para>
+
+<para>
+As when some cruel spite has befallen a man that he should have
+killed some one in his own country, and must fly to a great man's
+protection in a land of strangers, and all marvel who see him,
+even so did Achilles marvel as he beheld Priam. The others looked
+one to another and marvelled also, but Priam besought Achilles
+saying, "Think of your father, O Achilles like unto the gods, who
+is such even as I am, on the sad threshold of old age. It may be
+that those who dwell near him harass him, and there is none to
+keep war and ruin from him. Yet when he hears of you being still
+alive, he is glad, and his days are full of hope that he shall
+see his dear son come home to him from Troy; but I, wretched man
+that I am, had the bravest in all Troy for my sons, and there is
+not one of them left. I had fifty sons when the Achaeans came
+here; nineteen of them were from a single womb, and the others
+were borne to me by the women of my household. The greater part
+of them has fierce Mars laid low, and Hector, him who was alone
+left, him who was the guardian of the city and ourselves, him
+have you lately slain; therefore I am now come to the ships of
+the Achaeans to ransom his body from you with a great ransom.
+Fear, O Achilles, the wrath of heaven; think on your own father
+and have compassion upon me, who am the more pitiable, for I have
+steeled myself as no man yet has ever steeled himself before me,
+and have raised to my lips the hand of him who slew my son."
+</para>
+
+<para>
+Thus spoke Priam, and the heart of Achilles yearned as he
+bethought him of his father. He took the old man's hand and moved
+him gently away. The two wept bitterly--Priam, as he lay at
+Achilles' feet, weeping for Hector, and Achilles now for his
+father and now for Patroclous, till the house was filled with
+their lamentation. But when Achilles was now sated with grief and
+had unburthened the bitterness of his sorrow, he left his seat
+and raised the old man by the hand, in pity for his white hair
+and beard; then he said, "Unhappy man, you have indeed been
+greatly daring; how could you venture to come alone to the ships
+of the Achaeans, and enter the presence of him who has slain so
+many of your brave sons? You must have iron courage: sit now upon
+this seat, and for all our grief we will hide our sorrows in our
+hearts, for weeping will not avail us. The immortals know no
+care, yet the lot they spin for man is full of sorrow; on the
+floor of Jove's palace there stand two urns, the one filled with
+evil gifts, and the other with good ones. He for whom Jove the
+lord of thunder mixes the gifts he sends, will meet now with good
+and now with evil fortune; but he to whom Jove sends none but
+evil gifts will be pointed at by the finger of scorn, the hand of
+famine will pursue him to the ends of the world, and he will go
+up and down the face of the earth, respected neither by gods nor
+men. Even so did it befall Peleus; the gods endowed him with all
+good things from his birth upwards, for he reigned over the
+Myrmidons excelling all men in prosperity and wealth, and mortal
+though he was they gave him a goddess for his bride. But even on
+him too did heaven send misfortune, for there is no race of royal
+children born to him in his house, save one son who is doomed to
+die all untimely; nor may I take care of him now that he is
+growing old, for I must stay here at Troy to be the bane of you
+and your children. And you too, O Priam, I have heard that you
+were aforetime happy. They say that in wealth and plenitude of
+offspring you surpassed all that is in Lesbos, the realm of Makar
+to the northward, Phrygia that is more inland, and those that
+dwell upon the great Hellespont; but from the day when the
+dwellers in heaven sent this evil upon you, war and slaughter
+have been about your city continually. Bear up against it, and
+let there be some intervals in your sorrow. Mourn as you may for
+your brave son, you will take nothing by it. You cannot raise him
+from the dead, ere you do so yet another sorrow shall befall
+you."
+</para>
+
+<para>
+And Priam answered, "O king, bid me not be seated, while Hector
+is still lying uncared for in your tents, but accept the great
+ransom which I have brought you, and give him to me at once that
+I may look upon him. May you prosper with the ransom and reach
+your own land in safety, seeing that you have suffered me to live
+and to look upon the light of the sun."
+</para>
+
+<para>
+Achilles looked at him sternly and said, "Vex me, sir, no longer;
+I am of myself minded to give up the body of Hector. My mother,
+daughter of the old man of the sea, came to me from Jove to bid
+me deliver it to you. Moreover I know well, O Priam, and you
+cannot hide it, that some god has brought you to the ships of the
+Achaeans, for else, no man however strong and in his prime would
+dare to come to our host; he could neither pass our guard unseen,
+nor draw the bolt of my gates thus easily; therefore, provoke me
+no further, lest I sin against the word of Jove, and suffer you
+not, suppliant though you are, within my tents."
+</para>
+
+<para>
+The old man feared him and obeyed. Then the son of Peleus sprang
+like a lion through the door of his house, not alone, but with
+him went his two squires Automedon and Alcimus who were closer to
+him than any others of his comrades now that Patroclus was no
+more. These unyoked the horses and mules, and bade Priam's herald
+and attendant be seated within the house. They lifted the ransom
+for Hector's body from the waggon. but they left two mantles and
+a goodly shirt, that Achilles might wrap the body in them when he
+gave it to be taken home. Then he called to his servants and
+ordered them to wash the body and anoint it, but he first took it
+to a place where Priam should not see it, lest if he did so, he
+should break out in the bitterness of his grief, and enrage
+Achilles, who might then kill him and sin against the word of
+Jove. When the servants had washed the body and anointed it, and
+had wrapped it in a fair shirt and mantle, Achilles himself
+lifted it on to a bier, and he and his men then laid it on the
+waggon. He cried aloud as he did so and called on the name of his
+dear comrade, "Be not angry with me, Patroclus," he said, "if you
+hear even in the house of Hades that I have given Hector to his
+father for a ransom. It has been no unworthy one, and I will
+share it equitably with you."
+</para>
+
+<para>
+Achilles then went back into the tent and took his place on the
+richly inlaid seat from which he had risen, by the wall that was
+at right angles to the one against which Priam was sitting.
+"Sir," he said, "your son is now laid upon his bier and is
+ransomed according to desire; you shall look upon him when you
+him away at daybreak; for the present let us prepare our supper.
+Even lovely Niobe had to think about eating, though her twelve
+children--six daughters and six lusty sons--had been all slain in
+her house. Apollo killed the sons with arrows from his silver
+bow, to punish Niobe, and Diana slew the daughters, because Niobe
+had vaunted herself against Leto; she said Leto had borne two
+children only, whereas she had herself borne many--whereon the
+two killed the many. Nine days did they lie weltering, and there
+was none to bury them, for the son of Saturn turned the people
+into stone; but on the tenth day the gods in heaven themselves
+buried them, and Niobe then took food, being worn out with
+weeping. They say that somewhere among the rocks on the mountain
+pastures of Sipylus, where the nymphs live that haunt the river
+Achelous, there, they say, she lives in stone and still nurses
+the sorrows sent upon her by the hand of heaven. Therefore, noble
+sir, let us two now take food; you can weep for your dear son
+hereafter as you are bearing him back to Ilius--and many a tear
+will he cost you."
+</para>
+
+<para>
+With this Achilles sprang from his seat and killed a sheep of
+silvery whiteness, which his followers skinned and made ready all
+in due order. They cut the meat carefully up into smaller pieces,
+spitted them, and drew them off again when they were well
+roasted. Automedon brought bread in fair baskets and served it
+round the table, while Achilles dealt out the meat, and they laid
+their hands on the good things that were before them. As soon as
+they had had enough to eat and drink, Priam, descendant of
+Dardanus, marvelled at the strength and beauty of Achilles for he
+was as a god to see, and Achilles marvelled at Priam as he
+listened to him and looked upon his noble presence. When they had
+gazed their fill Priam spoke first. "And now, O king," he said,
+"take me to my couch that we may lie down and enjoy the blessed
+boon of sleep. Never once have my eyes been closed from the day
+your hands took the life of my son; I have grovelled without
+ceasing in the mire of my stable-yard, making moan and brooding
+over my countless sorrows. Now, moreover, I have eaten bread and
+drunk wine; hitherto I have tasted nothing."
+</para>
+
+<para>
+As he spoke Achilles told his men and the women-servants to set
+beds in the room that was in the gatehouse, and make them with
+good red rugs, and spread coverlets on the top of them with
+woollen cloaks for Priam and Idaeus to wear. So the maids went
+out carrying a torch and got the two beds ready in all haste.
+Then Achilles said laughingly to Priam, "Dear sir, you shall lie
+outside, lest some counsellor of those who in due course keep
+coming to advise with me should see you here in the darkness of
+the flying night, and tell it to Agamemnon. This might cause
+delay in the delivery of the body. And now tell me and tell me
+true, for how many days would you celebrate the funeral rites of
+noble Hector? Tell me, that I may hold aloof from war and
+restrain the host."
+</para>
+
+<para>
+And Priam answered, "Since, then, you suffer me to bury my noble
+son with all due rites, do thus, Achilles, and I shall be
+grateful. You know how we are pent up within our city; it is far
+for us to fetch wood from the mountain, and the people live in
+fear. Nine days, therefore, will we mourn Hector in my house; on
+the tenth day we will bury him and there shall be a public feast
+in his honour; on the eleventh we will build a mound over his
+ashes, and on the twelfth, if there be need, we will fight."
+</para>
+
+<para>
+And Achilles answered, "All, King Priam, shall be as you have
+said. I will stay our fighting for as long a time as you have
+named."
+</para>
+
+<para>
+As he spoke he laid his hand on the old man's right wrist, in
+token that he should have no fear; thus then did Priam and his
+attendant sleep there in the forecourt, full of thought, while
+Achilles lay in an inner room of the house, with fair Briseis by
+his side.
+</para>
+
+<para>
+And now both gods and mortals were fast asleep through the
+livelong night, but upon Mercury alone, the bringer of good luck,
+sleep could take no hold for he was thinking all the time how to
+get King Priam away from the ships without his being seen by the
+strong force of sentinels. He hovered therefore over Priam's head
+and said, "Sir, now that Achilles has spared your life, you seem
+to have no fear about sleeping in the thick of your foes. You
+have paid a great ransom, and have received the body of your son;
+were you still alive and a prisoner the sons whom you have left
+at home would have to give three times as much to free you; and
+so it would be if Agamemnon and the other Achaeans were to know
+of your being here."
+</para>
+
+<para>
+When he heard this the old man was afraid and roused his servant.
+Mercury then yoked their horses and mules, and drove them quickly
+through the host so that no man perceived them. When they came to
+the ford of eddying Xanthus, begotten of immortal Jove, Mercury
+went back to high Olympus, and dawn in robe of saffron began to
+break over all the land. Priam and Idaeus then drove on toward
+the city lamenting and making moan, and the mules drew the body
+of Hector. No one neither man nor woman saw them, till Cassandra,
+fair as golden Venus standing on Pergamus, caught sight of her
+dear father in his chariot, and his servant that was the city's
+herald with him. Then she saw him that was lying upon the bier,
+drawn by the mules, and with a loud cry she went about the city
+saying, "Come hither Trojans, men and women, and look on Hector;
+if ever you rejoiced to see him coming from battle when he was
+alive, look now on him that was the glory of our city and all our
+people."
+</para>
+
+<para>
+At this there was not man nor woman left in the city, so great a
+sorrow had possessed them. Hard by the gates they met Priam as he
+was bringing in the body. Hector's wife and his mother were the
+first to mourn him: they flew towards the waggon and laid their
+hands upon his head, while the crowd stood weeping round them.
+They would have stayed before the gates, weeping and lamenting
+the livelong day to the going down of the sun, had not Priam
+spoken to them from the chariot and said, "Make way for the mules
+to pass you. Afterwards when I have taken the body home you shall
+have your fill of weeping."
+</para>
+
+<para>
+On this the people stood asunder, and made a way for the waggon.
+When they had borne the body within the house they laid it upon a
+bed and seated minstrels round it to lead the dirge, whereon the
+women joined in the sad music of their lament. Foremost among
+them all Andromache led their wailing as she clasped the head of
+mighty Hector in her embrace. "Husband," she cried, "you have
+died young, and leave me in your house a widow; he of whom we are
+the ill-starred parents is still a mere child, and I fear he may
+not reach manhood. Ere he can do so our city will be razed and
+overthrown, for you who watched over it are no more--you who were
+its saviour, the guardian of our wives and children. Our women
+will be carried away captives to the ships, and I among them;
+while you, my child, who will be with me will be put to some
+unseemly tasks, working for a cruel master. Or, may be, some
+Achaean will hurl you (O miserable death) from our walls, to
+avenge some brother, son, or father whom Hector slew; many of
+them have indeed bitten the dust at his hands, for your father's
+hand in battle was no light one. Therefore do the people mourn
+him. You have left, O Hector, sorrow unutterable to your parents,
+and my own grief is greatest of all, for you did not stretch
+forth your arms and embrace me as you lay dying, nor say to me
+any words that might have lived with me in my tears night and day
+for evermore."
+</para>
+
+<para>
+Bitterly did she weep the while, and the women joined in her
+lament. Hecuba in her turn took up the strains of woe. "Hector,"
+she cried, "dearest to me of all my children. So long as you were
+alive the gods loved you well, and even in death they have not
+been utterly unmindful of you; for when Achilles took any other
+of my sons, he would sell him beyond the seas, to Samos Imbrus or
+rugged Lemnos; and when he had slain you too with his sword, many
+a time did he drag you round the sepulchre of his comrade--though
+this could not give him life--yet here you lie all fresh as dew,
+and comely as one whom Apollo has slain with his painless
+shafts."
+</para>
+
+<para>
+Thus did she too speak through her tears with bitter moan, and
+then Helen for a third time took up the strain of lamentation.
+"Hector," said she, "dearest of all my brothers-in-law--for I am
+wife to Alexandrus who brought me hither to Troy--would that I
+had died ere he did so--twenty years are come and gone since I
+left my home and came from over the sea, but I have never heard
+one word of insult or unkindness from you. When another would
+chide with me, as it might be one of your brothers or sisters or
+of your brothers' wives, or my mother-in-law--for Priam was as
+kind to me as though he were my own father--you would rebuke and
+check them with words of gentleness and goodwill. Therefore my
+tears flow both for you and for my unhappy self, for there is no
+one else in Troy who is kind to me, but all shrink and shudder as
+they go by me."
+</para>
+
+<para>
+She wept as she spoke and the vast crowd that was gathered round
+her joined in her lament. Then King Priam spoke to them saying,
+"Bring wood, O Trojans, to the city, and fear no cunning ambush
+of the Argives, for Achilles when he dismissed me from the ships
+gave me his word that they should not attack us until the morning
+of the twelfth day."
+</para>
+
+<para>
+Forthwith they yoked their oxen and mules and gathered together
+before the city. Nine days long did they bring in great heaps of
+wood, and on the morning of the tenth day with many tears they
+took brave Hector forth, laid his dead body upon the summit of
+the pile, and set the fire thereto. Then when the child of
+morning, rosy-fingered dawn, appeared on the eleventh day, the
+people again assembled, round the pyre of mighty Hector. When
+they were got together, they first quenched the fire with wine
+wherever it was burning, and then his brothers and comrades with
+many a bitter tear gathered his white bones, wrapped them in soft
+robes of purple, and laid them in a golden urn, which they placed
+in a grave and covered over with large stones set close together.
+Then they built a barrow hurriedly over it keeping guard on every
+side lest the Achaeans should attack them before they had
+finished. When they had heaped up the barrow they went back again
+into the city, and being well assembled they held high feast in
+the house of Priam their king.
+</para>
+
+<para>
+Thus, then, did they celebrate the funeral of Hector tamer of
+horses.
+</para>
+</chapter>
+</bookbody>
+</book>
+<endgutblurb>
+End of The Project Gutenberg Etext of The Iliad of Homer,
+translated by Samuel Butler
+</endgutblurb>
+
+</gutbook>
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/import/origin.xml
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/import/origin.xml	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/import/origin.xml	(revision 14125)
@@ -0,0 +1,17770 @@
+<?xml version="1.0"?>
+<!DOCTYPE gutbook SYSTEM "gutbook1.dtd">
+
+<?xml-stylesheet type="text/css" href="darwin.css"?>
+
+<gutbook>
+<gutblurb>
+<para>
+
+Project Gutenberg's Etext of On the Origin of Species, by Darwin
+#3 in our series by Charles Darwin
+</para>
+
+<para>
+This Etext is based on the First Edition, we are also working on
+the Sixth Edition, which many believe to be the best edition.
+</para>
+
+<para>
+
+Copyright laws are changing all over the world, be sure to check
+the copyright laws for your country before posting these files!!
+</para>
+
+<para>
+Please take a look at the important information in this header.
+We encourage you to keep this file on your own disk, keeping an
+electronic path open for the next readers.  Do not remove this.
+</para>
+
+<para>
+
+**Welcome To The World of Free Plain Vanilla Electronic Texts**
+</para>
+
+<para>
+**Etexts Readable By Both Humans and By Computers, Since 1971**
+</para>
+
+<para>
+*These Etexts Prepared By Hundreds of Volunteers and Donations*
+</para>
+
+<para>
+Information on contacting Project Gutenberg to get Etexts, and
+further information is included below.  We need your donations.
+</para>
+
+<para>
+
+On the Origin of Species
+</para>
+
+<para>
+by Charles Darwin
+</para>
+
+<para>
+March, 1998  [Etext #1228]
+</para>
+
+<para>
+
+Project Gutenberg's Etext of On the Origin of Species, by Darwin
+******This file should be named 1rbnh10.txt or 1rbnh10.zip******
+</para>
+
+<para>
+Corrected EDITIONS of our etexts get a new NUMBER, 1rbnh11.txt
+VERSIONS based on separate sources get new LETTER, 1rbnh10a.txt
+</para>
+
+<para>
+
+This etext was prepared by Joseph S. Miller, Pensacola, FL and
+Embry-Riddle Aeronautical University Library, Prescott, AZ.
+</para>
+
+<para>
+Project Gutenberg Etexts are usually created from multiple editions,
+all of which are in the Public Domain in the United States, unless a
+copyright notice is included.  Therefore, we do NOT keep these books
+in compliance with any particular paper edition, usually otherwise.
+</para>
+
+<para>
+
+We are now trying to release all our books one month in advance
+of the official release dates, for time for better editing.
+</para>
+
+<para>
+Please note:  neither this list nor its contents are final till
+midnight of the last day of the month of any such announcement.
+The official release date of all Project Gutenberg Etexts is at
+Midnight, Central Time, of the last day of the stated month.  A
+preliminary version may often be posted for suggestion, comment
+and editing by those who wish to do so.  To be sure you have an
+up to date first edition [xxxxx10x.xxx] please check file sizes
+in the first week of the next month.  Since our ftp program has
+a bug in it that scrambles the date [tried to fix and failed] a
+look at the file size will have to do, but we will try to see a
+new copy has at least one byte more or less.
+</para>
+
+<para>
+
+Information about Project Gutenberg (one page)
+</para>
+
+<para>
+We produce about two million dollars for each hour we work.  The
+fifty hours is one conservative estimate for how long it we take
+to get any etext selected, entered, proofread, edited, copyright
+searched and analyzed, the copyright letters written, etc.  This
+projected audience is one hundred million readers.  If our value
+per text is nominally estimated at one dollar then we produce $2
+million dollars per hour this year as we release thirty-two text
+files per month, or 384 more Etexts in 1998 for a total of 1500+
+If these reach just 10% of the computerized population, then the
+total should reach over 150 billion Etexts given away.
+</para>
+
+<para>
+The Goal of Project Gutenberg is to Give Away One Trillion Etext
+Files by the December 31, 2001.  [10,000 x 100,000,000=Trillion]
+This is ten thousand titles each to one hundred million readers,
+which is only 10% of the present number of computer users.  2001
+should have at least twice as many computer users as that, so it
+will require us reaching less than 5% of the users in 2001.
+</para>
+
+<para>
+
+We need your donations more than ever!
+</para>
+
+<para>
+
+All donations should be made to "Project Gutenberg/CMU": and are
+tax deductible to the extent allowable by law.  (CMU = Carnegie-
+Mellon University).
+</para>
+
+<para>
+For these and other matters, please mail to:
+</para>
+
+<para>
+Project Gutenberg
+P. O. Box  2782
+Champaign, IL 61825
+</para>
+
+<para>
+When all other email fails try our Executive Director:
+Michael S. Hart &lt;hart@pobox.com>
+</para>
+
+<para>
+We would prefer to send you this information by email
+(Internet, Bitnet, Compuserve, ATTMAIL or MCImail).
+</para>
+
+<para>
+******
+If you have an FTP program (or emulator), please
+FTP directly to the Project Gutenberg archives:
+[Mac users, do NOT point and click. . .type]
+</para>
+
+<para>
+ftp uiarchive.cso.uiuc.edu
+login:  anonymous
+password:  your@login
+cd etext/etext90 through /etext96
+or cd etext/articles [get suggest gut for more information]
+dir [to see files]
+get or mget [to get files. . .set bin for zip files]
+GET INDEX?00.GUT
+for a list of books
+and
+GET NEW GUT for general information
+and
+MGET GUT* for newsletters.
+</para>
+
+<para>
+**Information prepared by the Project Gutenberg legal advisor**
+(Three Pages)
+</para>
+
+<para>
+
+***START**THE SMALL PRINT!**FOR PUBLIC DOMAIN ETEXTS**START***
+Why is this "Small Print!" statement here?  You know: lawyers.
+They tell us you might sue us if there is something wrong with
+your copy of this etext, even if you got it for free from
+someone other than us, and even if what's wrong is not our
+fault.  So, among other things, this "Small Print!" statement
+disclaims most of our liability to you.  It also tells you how
+you can distribute copies of this etext if you want to.
+</para>
+
+<para>
+*BEFORE!* YOU USE OR READ THIS ETEXT
+By using or reading any part of this PROJECT GUTENBERG-tm
+etext, you indicate that you understand, agree to and accept
+this "Small Print!" statement.  If you do not, you can receive
+a refund of the money (if any) you paid for this etext by
+sending a request within 30 days of receiving it to the person
+you got it from.  If you received this etext on a physical
+medium (such as a disk), you must return it with your request.
+</para>
+
+<para>
+ABOUT PROJECT GUTENBERG-TM ETEXTS
+This PROJECT GUTENBERG-tm etext, like most PROJECT GUTENBERG-
+tm etexts, is a "public domain" work distributed by Professor
+Michael S. Hart through the Project Gutenberg Association at
+Carnegie-Mellon University (the "Project").  Among other
+things, this means that no one owns a United States copyright
+on or for this work, so the Project (and you!) can copy and
+distribute it in the United States without permission and
+without paying copyright royalties.  Special rules, set forth
+below, apply if you wish to copy and distribute this etext
+under the Project's "PROJECT GUTENBERG" trademark.
+</para>
+
+<para>
+To create these etexts, the Project expends considerable
+efforts to identify, transcribe and proofread public domain
+works.  Despite these efforts, the Project's etexts and any
+medium they may be on may contain "Defects".  Among other
+things, Defects may take the form of incomplete, inaccurate or
+corrupt data, transcription errors, a copyright or other
+intellectual property infringement, a defective or damaged
+disk or other etext medium, a computer virus, or computer
+codes that damage or cannot be read by your equipment.
+</para>
+
+<para>
+LIMITED WARRANTY; DISCLAIMER OF DAMAGES
+But for the "Right of Replacement or Refund" described below,
+[1] the Project (and any other party you may receive this
+etext from as a PROJECT GUTENBERG-tm etext) disclaims all
+liability to you for damages, costs and expenses, including
+legal fees, and [2] YOU HAVE NO REMEDIES FOR NEGLIGENCE OR
+UNDER STRICT LIABILITY, OR FOR BREACH OF WARRANTY OR CONTRACT,
+INCLUDING BUT NOT LIMITED TO INDIRECT, CONSEQUENTIAL, PUNITIVE
+OR INCIDENTAL DAMAGES, EVEN IF YOU GIVE NOTICE OF THE
+POSSIBILITY OF SUCH DAMAGES.
+</para>
+
+<para>
+If you discover a Defect in this etext within 90 days of
+receiving it, you can receive a refund of the money (if any)
+you paid for it by sending an explanatory note within that
+time to the person you received it from.  If you received it
+on a physical medium, you must return it with your note, and
+such person may choose to alternatively give you a replacement
+copy.  If you received it electronically, such person may
+choose to alternatively give you a second opportunity to
+receive it electronically.
+</para>
+
+<para>
+THIS ETEXT IS OTHERWISE PROVIDED TO YOU "AS-IS".  NO OTHER
+WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, ARE MADE TO YOU AS
+TO THE ETEXT OR ANY MEDIUM IT MAY BE ON, INCLUDING BUT NOT
+LIMITED TO WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
+PARTICULAR PURPOSE.
+</para>
+
+<para>
+Some states do not allow disclaimers of implied warranties or
+the exclusion or limitation of consequential damages, so the
+above disclaimers and exclusions may not apply to you, and you
+may have other legal rights.
+</para>
+
+<para>
+INDEMNITY
+You will indemnify and hold the Project, its directors,
+officers, members and agents harmless from all liability, cost
+and expense, including legal fees, that arise directly or
+indirectly from any of the following that you do or cause:
+[1] distribution of this etext, [2] alteration, modification,
+or addition to the etext, or [3] any Defect.
+</para>
+
+<para>
+DISTRIBUTION UNDER "PROJECT GUTENBERG-tm"
+You may distribute copies of this etext electronically, or by
+disk, book or any other medium if you either delete this
+"Small Print!" and all other references to Project Gutenberg,
+or:
+</para>
+
+<para>
+[1]  Only give exact copies of it.  Among other things, this
+     requires that you do not remove, alter or modify the
+     etext or this "small print!" statement.  You may however,
+     if you wish, distribute this etext in machine readable
+     binary, compressed, mark-up, or proprietary form,
+     including any form resulting from conversion by word pro-
+     cessing or hypertext software, but only so long as
+     *EITHER*:
+</para>
+
+<para>
+     [*]  The etext, when displayed, is clearly readable, and
+          does *not* contain characters other than those
+          intended by the author of the work, although tilde
+          (~), asterisk (*) and underline (_) characters may
+          be used to convey punctuation intended by the
+          author, and additional characters may be used to
+          indicate hypertext links; OR
+</para>
+
+<para>
+     [*]  The etext may be readily converted by the reader at
+          no expense into plain ASCII, EBCDIC or equivalent
+          form by the program that displays the etext (as is
+          the case, for instance, with most word processors);
+          OR
+</para>
+
+<para>
+     [*]  You provide, or agree to also provide on request at
+          no additional cost, fee or expense, a copy of the
+          etext in its original plain ASCII form (or in EBCDIC
+          or other equivalent proprietary form).
+</para>
+
+<para>
+[2]  Honor the etext refund and replacement provisions of this
+     "Small Print!" statement.
+</para>
+
+<para>
+[3]  Pay a trademark license fee to the Project of 20% of the
+     net profits you derive calculated using the method you
+     already use to calculate your applicable taxes.  If you
+     don't derive profits, no royalty is due.  Royalties are
+     payable to "Project Gutenberg Association/Carnegie-Mellon
+     University" within the 60 days following each
+     date you prepare (or were legally required to prepare)
+     your annual (or equivalent periodic) tax return.
+</para>
+
+<para>
+WHAT IF YOU *WANT* TO SEND MONEY EVEN IF YOU DON'T HAVE TO?
+The Project gratefully accepts contributions in money, time,
+scanning machines, OCR software, public domain etexts, royalty
+free copyright licenses, and every other sort of contribution
+you can think of.  Money should be paid to "Project Gutenberg
+Association / Carnegie-Mellon University".
+</para>
+
+<para>
+*END*THE SMALL PRINT! FOR PUBLIC DOMAIN ETEXTS*Ver.04.29.93*END*
+</para>
+
+</gutblurb>
+<markupblurb>
+Frank Boumphrey 9:25 AM 1/24/00
+Validated using MSXML and gutbook1.dtd
+</markupblurb>
+
+<book>
+<acknowledge>'On the Origin of Species' by Charles Darwin.
+  A project of Project Gutenberg and the HTML Writers Guild.
+  Transcribed by  Joseph S. Miller and
+Embry-Riddle Aeronautical University Library.
+  Markup by Frank Boumphrey. Jan 22 2000.
+For more details view the source document.
+</acknowledge>
+<frontmatter>
+<htitlepage>
+<title>
+On the Origin of Species
+</title>
+
+<author>
+by Charles Darwin
+</author>
+</htitlepage>
+
+<epigraph>
+<blockquote>
+<para>
+'But with regard to the material world, we can at least go so far as this--
+we can perceive that events are brought about not by insulated
+interpositions of Divine power, exerted in each particular case, but by the
+establishment of general laws.'
+</para>
+
+<attrib>
+W. Whewell: Bridgewater Treatise.
+</attrib>
+</blockquote>
+
+<blockquote>
+<para>
+'To conclude, therefore, let no man out of a weak conceit of sobriety, or
+an ill-applied moderation, think or maintain, that a man can search too far
+or be too well studied in the book of God's word, or in the book of God's
+works; divinity or philosophy; but rather let men endeavour an endless
+progress or proficience in both.'
+</para>
+
+<attrib>
+Bacon: Advancement of Learning.
+</attrib>
+</blockquote>
+
+
+<para>
+
+<place>Down, Bromley, Kent,</place> 
+</para>
+
+<para>
+<date>October 1st, 1859.</date>
+</para>
+</epigraph>
+
+<titlepage>
+<title>
+On the Origin of Species by Means of Natural Selection, 
+</title>
+
+<para>
+or the
+</para>
+
+<subtitle>
+Preservation of Favoured Races in the Struggle for Life.
+</subtitle>
+
+<author>
+By Charles Darwin
+</author>
+
+</titlepage>
+
+<toc>
+<title>Contents</title>
+
+<deflist>
+
+<item>
+Introduction
+</item>
+
+
+<item>
+Chapter I
+</item>
+
+<desc>
+Variation under Domestication
+</desc>
+
+<def>
+Causes of Variability -- Effects of Habit -- Correlation of Growth --
+Inheritance -- Character of Domestic Varieties -- Difficulty of
+distinguishing between Varieties and Species -- Origin of Domestic
+Varieties from one or more Species -- Domestic Pigeons, their Differences
+and Origin -- Principle of Selection anciently followed, its Effects --
+Methodical and Unconscious Selection -- Unknown Origin of our Domestic
+Productions -- Circumstances favourable to Man's power of Selection.
+</def>
+
+
+
+<item>
+Chapter II
+</item>
+
+<desc>
+Variation under Nature
+</desc>
+
+<def>
+Variability -- Individual Differences -- Doubtful species -- Wide ranging,
+much diffused, and common species vary most -- Species of the larger genera
+in any country vary more than the species of the smaller genera -- Many of
+the species of the larger genera resemble varieties in being very closely,
+but unequally, related to each other, and in having restricted ranges.
+</def>
+
+
+
+<item>
+Chapter III
+</item>
+
+<desc>
+Struggle for Existence
+</desc>
+
+<def>
+Bears on natural selection -- The term used in a wide sense -- Geometrical
+powers of increase -- Rapid increase of naturalised animals and plants --
+Nature of the checks to increase -- Competition universal -- Effects of
+climate -- Protection from the number of individuals -- Complex relations
+of all animals and plants throughout nature -- Struggle for life most
+severe between individuals and varieties of the same species; often severe
+between species of the same genus -- The relation of organism to organism
+the most important of all relations.
+</def>
+
+
+
+<item>
+Chapter IV
+</item>
+
+<desc>
+Natural Selection
+</desc>
+
+<def>
+Natural Selection -- its power compared with man's selection -- its power
+on characters of trifling importance -- its power at all ages and on both
+sexes -- Sexual Selection -- On the generality of intercrosses between
+individuals of the same species -- Circumstances favourable and
+unfavourable to Natural Selection, namely, intercrossing, isolation, number
+of individuals -- Slow action -- Extinction caused by Natural Selection --
+Divergence of Character, related to the diversity of inhabitants of any
+small area, and to naturalisation -- Action of Natural Selection, through
+Divergence of Character and Extinction, on the descendants from a common
+parent -- Explains the Grouping of all organic beings.
+</def>
+
+
+
+<item>
+Chapter V
+</item>
+
+<desc>
+Laws of Variation
+</desc>
+
+<def>
+Effects of external conditions -- Use and disuse, combined with natural
+selection; organs of flight and of vision -- Acclimatisation -- Correlation
+of growth -- Compensation and economy of growth -- False correlations --
+Multiple, rudimentary, and lowly organised structures variable -- Parts
+developed in an unusual manner are highly variable:  specific characters
+more variable than generic:  secondary sexual characters variable --
+Species of the same genus vary in an analogous manner -- Reversions to
+long-lost characters -- Summary.
+</def>
+
+
+
+<item>
+Chapter VI
+</item>
+
+<desc>
+Difficulties on Theory
+</desc>
+
+<def>
+Difficulties on the theory of descent with modification -- Transitions --
+Absence or rarity of transitional varieties -- Transitions in habits of
+life -- Diversified habits in the same species -- Species with habits
+widely different from those of their allies -- Organs of extreme perfection
+-- Means of transition -- Cases of difficulty -- Natura non facit saltum --
+Organs of small importance -- Organs not in all cases absolutely perfect --
+The law of Unity of Type and of the Conditions of Existence embraced by the
+theory of Natural Selection.
+</def>
+
+
+
+<item>
+Chapter VII
+</item>
+
+<desc>
+Instinct
+</desc>
+
+<def>
+Instincts comparable with habits, but different in their origin --
+Instincts graduated -- Aphides and ants -- Instincts variable -- Domestic
+instincts, their origin -- Natural instincts of the cuckoo, ostrich, and
+parasitic bees -- Slave-making ants -- Hive-bee, its cell-making instinct -
+- Difficulties on the theory of the Natural Selection of instincts --
+Neuter or sterile insects -- Summary.
+</def>
+
+
+
+<item>
+Chapter VIII
+</item>
+
+<desc>
+Hybridism
+</desc>
+
+<def>
+Distinction between the sterility of first crosses and of hybrids --
+Sterility various in degree, not universal, affected by close
+interbreeding, removed by domestication -- Laws governing the sterility of
+hybrids -- Sterility not a special endowment, but incidental on other
+differences -- Causes of the sterility of first crosses and of hybrids --
+Parallelism between the effects of changed conditions of life and crossing
+-- Fertility of varieties when crossed and of their mongrel offspring not
+universal -- Hybrids and mongrels compared independently of their fertility
+-- Summary.
+</def>
+
+
+
+<item>
+Chapter IX
+</item>
+
+<desc>
+On the Imperfection of the Geological Record
+</desc>
+
+<def>
+On the absence of intermediate varieties at the present day -- On the
+nature of extinct intermediate varieties; on their number -- On the vast
+lapse of time, as inferred from the rate of deposition and of denudation --
+On the poorness of our palaeontological collections -- On the intermittence
+of geological formations -- On the absence of intermediate varieties in any
+one formation -- On the sudden appearance of groups of species -- On their
+sudden appearance in the lowest known fossiliferous strata.
+</def>
+
+
+
+<item>
+Chapter X
+</item>
+
+<desc>
+On the Geological Succession of Organic Beings
+</desc>
+
+<def>
+On the slow and successive appearance of new species -- On their different
+rates of change -- Species once lost do not reappear -- Groups of species
+follow the same general rules in their appearance and disappearance as do
+single species -- On Extinction -- On simultaneous changes in the forms of
+life throughout the world -- On the affinities of extinct species to each
+other and to living species -- On the state of development of ancient forms
+-- On the succession of the same types within the same areas -- Summary of
+preceding and present chapters.
+</def>
+
+
+
+<item>
+Chapter XI
+</item>
+
+<desc>
+Geographical Distribution
+</desc>
+
+<def>
+Present distribution cannot be accounted for by differences in physical
+conditions -- Importance of barriers -- Affinity of the productions of the
+same continent -- Centres of creation -- Means of dispersal, by changes of
+climate and of the level of the land, and by occasional means -- Dispersal
+during the Glacial period co-extensive with the world.
+</def>
+
+
+
+<item>
+Chapter XII
+</item>
+
+<desc>
+Geographical Distribution -- continued
+</desc>
+
+<def>
+Distribution of fresh-water productions -- On the inhabitants of oceanic
+islands -- Absence of Batrachians and of terrestrial Mammals -- On the
+relation of the inhabitants of islands to those of the nearest mainland --
+On colonisation from the nearest source with subsequent modification --
+Summary of the last and present chapters.
+</def>
+
+
+
+<item>
+Chapter XIII
+</item>
+
+<desc>
+Mutual Affinities of Organic Beings:
+Morphology:  Embryology:  Rudimentary Organs
+</desc>
+
+<def>
+Classification, groups subordinate to groups -- Natural system -- Rules and
+difficulties in classification, explained on the theory of descent with
+modification -- Classification of varieties -- Descent always used in
+classification -- Analogical or adaptive characters -- Affinities, general,
+complex and radiating -- Extinction separates and defines groups --
+Morphology, between members of the same class, between parts of the same
+individual -- Embryology, laws of, explained by variations not supervening
+at an early age, and being inherited at a corresponding age -- Rudimentary
+Organs; their origin explained -- Summary.
+</def>
+
+
+
+<item>
+Chapter XIV
+</item>
+
+<desc>
+Recapitulation and Conclusion
+</desc>
+
+<def>
+Recapitulation of the difficulties on the theory of Natural Selection --
+Recapitulation of the general and special circumstances in its favour --
+Causes of the general belief in the immutability of species -- How far the
+theory of natural selection may be extended -- Effects of its adoption on
+the study of Natural history -- Concluding remarks.
+</def>
+</deflist>
+</toc>
+
+
+
+
+<introduction>
+<title>
+On the Origin of Species.
+
+Introduction.
+</title>
+
+<para>
+When on board H.M.S. 'Beagle,' as naturalist, I was much struck with
+certain facts in the distribution of the inhabitants of South America, and
+in the geological relations of the present to the past inhabitants of that
+continent.  These facts seemed to me to throw some light on the origin of
+species--that mystery of mysteries, as it has been called by one of our
+greatest philosophers.  On my return home, it occurred to me, in 1837, that
+something might perhaps be made out on this question by patiently
+accumulating and reflecting on all sorts of facts which could possibly have
+any bearing on it.  After five years' work I allowed myself to speculate on
+the subject, and drew up some short notes; these I enlarged in 1844 into a
+sketch of the conclusions, which then seemed to me probable:  from that
+period to the present day I have steadily pursued the same object.  I hope
+that I may be excused for entering on these personal details, as I give
+them to show that I have not been hasty in coming to a decision.
+</para>
+
+<para>
+My work is now nearly finished; but as it will take me two or three more
+years to complete it, and as my health is far from strong, I have been
+urged to publish this Abstract.  I have more especially been induced to do
+this, as Mr. Wallace, who is now studying the natural history of the Malay
+archipelago, has arrived at almost exactly the same general conclusions
+that I have on the origin of species.  Last year he sent to me a memoir on
+this subject, with a request that I would forward it to Sir Charles Lyell,
+who sent it to the Linnean Society, and it is published in the third volume
+of the Journal of that Society.  Sir C. Lyell and Dr. Hooker, who both knew
+of my work--the latter having read my sketch of 1844--honoured me by
+thinking it advisable to publish, with Mr. Wallace's excellent memoir, some
+brief extracts from my manuscripts.
+</para>
+
+<para>
+This Abstract, which I now publish, must necessarily be imperfect.  I
+cannot here give references and authorities for my several statements; and
+I must trust to the reader reposing some confidence in my accuracy.  No
+doubt errors will have crept in, though I hope I have always been cautious
+in trusting to good authorities alone.  I can here give only the general
+conclusions at which I have arrived, with a few facts in illustration, but
+which, I hope, in most cases will suffice.  No one can feel more sensible
+than I do of the necessity of hereafter publishing in detail all the facts,
+with references, on which my conclusions have been grounded; and I hope in
+a future work to do this.  For I am well aware that scarcely a single point
+is discussed in this volume on which facts cannot be adduced, often
+apparently leading to conclusions directly opposite to those at which I
+have arrived.  A fair result can be obtained only by fully stating and
+balancing the facts and arguments on both sides of each question; and this
+cannot possibly be here done.
+</para>
+
+<para>
+I much regret that want of space prevents my having the satisfaction of
+acknowledging the generous assistance which I have received from very many
+naturalists, some of them personally unknown to me.  I cannot, however, let
+this opportunity pass without expressing my deep obligations to Dr. Hooker,
+who for the last fifteen years has aided me in every possible way by his
+large stores of knowledge and his excellent judgment.
+</para>
+
+<para>
+In considering the Origin of Species, it is quite conceivable that a
+naturalist, reflecting on the mutual affinities of organic beings, on their
+embryological relations, their geographical distribution, geological
+succession, and other such facts, might come to the conclusion that each
+species had not been independently created, but had descended, like
+varieties, from other species.  Nevertheless, such a conclusion, even if
+well founded, would be unsatisfactory, until it could be shown how the
+innumerable species inhabiting this world have been modified, so as to
+acquire that perfection of structure and coadaptation which most justly
+excites our admiration.  Naturalists continually refer to external
+conditions, such as climate, food, &amp;c., as the only possible cause of
+variation.  In one very limited sense, as we shall hereafter see, this may
+be true; but it is preposterous to attribute to mere external conditions,
+the structure, for instance, of the woodpecker, with its feet, tail, beak,
+and tongue, so admirably adapted to catch insects under the bark of trees. 
+In the case of the misseltoe, which draws its nourishment from certain
+trees, which has seeds that must be transported by certain birds, and which
+has flowers with separate sexes absolutely requiring the agency of certain
+insects to bring pollen from one flower to the other, it is equally
+preposterous to account for the structure of this parasite, with its
+relations to several distinct organic beings, by the effects of external
+conditions, or of habit, or of the volition of the plant itself.
+</para>
+
+<para>
+The author of the 'Vestiges of Creation' would, I presume, say that, after
+a certain unknown number of generations, some bird had given birth to a
+woodpecker, and some plant to the misseltoe, and that these had been
+produced perfect as we now see them; but this assumption seems to me to be
+no explanation, for it leaves the case of the coadaptations of organic
+beings to each other and to their physical conditions of life, untouched
+and unexplained.
+</para>
+
+<para>
+It is, therefore, of the highest importance to gain a clear insight into
+the means of modification and coadaptation.  At the commencement of my
+observations it seemed to me probable that a careful study of domesticated
+animals and of cultivated plants would offer the best chance of making out
+this obscure problem.  Nor have I been disappointed; in this and in all
+other perplexing cases I have invariably found that our knowledge,
+imperfect though it be, of variation under domestication, afforded the best
+and safest clue.  I may venture to express my conviction of the high value
+of such studies, although they have been very commonly neglected by
+naturalists.
+</para>
+
+<para>
+From these considerations, I shall devote the first chapter of this
+Abstract to Variation under Domestication.  We shall thus see that a large
+amount of hereditary modification is at least possible, and, what is
+equally or more important, we shall see how great is the power of man in
+accumulating by his Selection successive slight variations.  I will then
+pass on to the variability of species in a state of nature; but I shall,
+unfortunately, be compelled to treat this subject far too briefly, as it
+can be treated properly only by giving long catalogues of facts.  We shall,
+however, be enabled to discuss what circumstances are most favourable to
+variation.  In the next chapter the Struggle for Existence amongst all
+organic beings throughout the world, which inevitably follows from their
+high geometrical powers of increase, will be treated of.  This is the
+doctrine of Malthus, applied to the whole animal and vegetable kingdoms. 
+As many more individuals of each species are born than can possibly
+survive; and as, consequently, there is a frequently recurring struggle for
+existence, it follows that any being, if it vary however slightly in any
+manner profitable to itself, under the complex and sometimes varying
+conditions of life, will have a better chance of surviving, and thus be
+naturally selected.  From the strong principle of inheritance, any selected
+variety will tend to propagate its new and modified form.
+</para>
+
+<para>
+This fundamental subject of Natural Selection will be treated at some
+length in the fourth chapter; and we shall then see how Natural Selection
+almost inevitably causes much Extinction of the less improved forms of life
+and induces what I have called Divergence of Character.  In the next
+chapter I shall discuss the complex and little known laws of variation and
+of correlation of growth.  In the four succeeding chapters, the most
+apparent and gravest difficulties on the theory will be given:  namely,
+first, the difficulties of transitions, or in understanding how a simple
+being or a simple organ can be changed and perfected into a highly
+developed being or elaborately constructed organ; secondly the subject of
+Instinct, or the mental powers of animals, thirdly, Hybridism, or the
+infertility of species and the fertility of varieties when intercrossed;
+and fourthly, the imperfection of the Geological Record.  In the next
+chapter I shall consider the geological succession of organic beings
+throughout time; in the eleventh and twelfth, their geographical
+distribution throughout space; in the thirteenth, their classification or
+mutual affinities, both when mature and in an embryonic condition.  In the
+last chapter I shall give a brief recapitulation of the whole work, and a
+few concluding remarks.
+</para>
+
+<para>
+No one ought to feel surprise at much remaining as yet unexplained in
+regard to the origin of species and varieties, if he makes due allowance
+for our profound ignorance in regard to the mutual relations of all the
+beings which live around us.  Who can explain why one species ranges widely
+and is very numerous, and why another allied species has a narrow range and
+is rare?  Yet these relations are of the highest importance, for they
+determine the present welfare, and, as I believe, the future success and
+modification of every inhabitant of this world.  Still less do we know of
+the mutual relations of the innumerable inhabitants of the world during the
+many past geological epochs in its history.  Although much remains obscure,
+and will long remain obscure, I can entertain no doubt, after the most
+deliberate study and dispassionate judgment of which I am capable, that the
+view which most naturalists entertain, and which I formerly
+entertained--namely, that each species has been independently created--is
+erroneous.  I am fully convinced that species are not immutable; but that
+those belonging to what are called the same genera are lineal descendants
+of some other and generally extinct species, in the same manner as the
+acknowledged varieties of any one species are the descendants of that
+species.  Furthermore, I am convinced that Natural Selection has been the
+main but not exclusive means of modification.
+</para>
+</introduction>
+</frontmatter>
+<bookbody>
+
+<chapter>
+<chapheader>
+
+<chapnum>Chapter I</chapnum>
+
+<title>Variation under Domestication</title>
+
+<chapsummary>
+Causes of Variability -- Effects of Habit -- Correlation of Growth --
+Inheritance -- Character of Domestic Varieties -- Difficulty of
+distinguishing between Varieties and Species -- Origin of Domestic
+Varieties from one or more Species -- Domestic Pigeons, their Differences
+and Origin -- Principle of Selection anciently followed, its Effects --
+Methodical and Unconscious Selection -- Unknown Origin of our Domestic
+Productions -- Circumstances favourable to Man's power of Selection.
+</chapsummary>
+</chapheader>
+
+<para>
+When we look to the individuals of the same variety or sub-variety of our
+older cultivated plants and animals, one of the first points which strikes
+us, is, that they generally differ much more from each other, than do the
+individuals of any one species or variety in a state of nature.  When we
+reflect on the vast diversity of the plants and animals which have been
+cultivated, and which have varied during all ages under the most different
+climates and treatment, I think we are driven to conclude that this greater
+variability is simply due to our domestic productions having been raised
+under conditions of life not so uniform as, and somewhat different from,
+those to which the parent-species have been exposed under nature.  There
+is, also, I think, some probability in the view propounded by Andrew
+Knight, that this variability may be partly connected with excess of food. 
+It seems pretty clear that organic beings must be exposed during several
+generations to the new conditions of life to cause any appreciable amount
+of variation; and that when the organisation has once begun to vary, it
+generally continues to vary for many generations.  No case is on record of
+a variable being ceasing to be variable under cultivation.  Our oldest
+cultivated plants, such as wheat, still often yield new varieties:  our
+oldest domesticated animals are still capable of rapid improvement or
+modification.
+</para>
+
+<para>
+It has been disputed at what period of life the causes of variability,
+whatever they may be, generally act; whether during the early or late
+period of development of the embryo, or at the instant of conception. 
+Geoffroy St. Hilaire's experiments show that unnatural treatment of the
+embryo causes monstrosities; and monstrosities cannot be separated by any
+clear line of distinction from mere variations.  But I am strongly inclined
+to suspect that the most frequent cause of variability may be attributed to
+the male and female reproductive elements having been affected prior to the
+act of conception.  Several reasons make me believe in this; but the chief
+one is the remarkable effect which confinement or cultivation has on the
+functions of the reproductive system; this system appearing to be far more
+susceptible than any other part of the organisation, to the action of any
+change in the conditions of life.  Nothing is more easy than to tame an
+animal, and few things more difficult than to get it to breed freely under
+confinement, even in the many cases when the male and female unite.  How
+many animals there are which will not breed, though living long under not
+very close confinement in their native country!  This is generally
+attributed to vitiated instincts; but how many cultivated plants display
+the utmost vigour, and yet rarely or never seed!  In some few such cases it
+has been found out that very trifling changes, such as a little more or
+less water at some particular period of growth, will determine whether or
+not the plant sets a seed.  I cannot here enter on the copious details
+which I have collected on this curious subject; but to show how singular
+the laws are which determine the reproduction of animals under confinement,
+I may just mention that carnivorous animals, even from the tropics, breed
+in this country pretty freely under confinement, with the exception of the
+plantigrades or bear family; whereas, carnivorous birds, with the rarest
+exceptions, hardly ever lay fertile eggs.  Many exotic plants have pollen
+utterly worthless, in the same exact condition as in the most sterile
+hybrids.  When, on the one hand, we see domesticated animals and plants,
+though often weak and sickly, yet breeding quite freely under confinement;
+and when, on the other hand, we see individuals, though taken young from a
+state of nature, perfectly tamed, long-lived, and healthy (of which I could
+give numerous instances), yet having their reproductive system so seriously
+affected by unperceived causes as to fail in acting, we need not be
+surprised at this system, when it does act under confinement, acting not
+quite regularly, and producing offspring not perfectly like their parents
+or variable.
+</para>
+
+<para>
+Sterility has been said to be the bane of horticulture; but on this view we
+owe variability to the same cause which produces sterility; and variability
+is the source of all the choicest productions of the garden.  I may add,
+that as some organisms will breed most freely under the most unnatural
+conditions (for instance, the rabbit and ferret kept in hutches), showing
+that their reproductive system has not been thus affected; so will some
+animals and plants withstand domestication or cultivation, and vary very
+slightly--perhaps hardly more than in a state of nature.
+</para>
+
+<para>
+A long list could easily be given of 'sporting plants;' by this term
+gardeners mean a single bud or offset, which suddenly assumes a new and
+sometimes very different character from that of the rest of the plant. 
+Such buds can be propagated by grafting, &amp;c., and sometimes by seed.  These
+'sports' are extremely rare under nature, but far from rare under
+cultivation; and in this case we see that the treatment of the parent has
+affected a bud or offset, and not the ovules or pollen.  But it is the
+opinion of most physiologists that there is no essential difference between
+a bud and an ovule in their earliest stages of formation; so that, in fact,
+'sports' support my view, that variability may be largely attributed to the
+ovules or pollen, or to both, having been affected by the treatment of the
+parent prior to the act of conception.  These cases anyhow show that
+variation is not necessarily connected, as some authors have supposed, with
+the act of generation.
+</para>
+
+<para>
+Seedlings from the same fruit, and the young of the same litter, sometimes
+differ considerably from each other, though both the young and the parents,
+as Muller has remarked, have apparently been exposed to exactly the same
+conditions of life; and this shows how unimportant the direct effects of
+the conditions of life are in comparison with the laws of reproduction, and
+of growth, and of inheritance; for had the action of the conditions been
+direct, if any of the young had varied, all would probably have varied in
+the same manner.  To judge how much, in the case of any variation, we
+should attribute to the direct action of heat, moisture, light, food, &amp;c.,
+is most difficult:  my impression is, that with animals such agencies have
+produced very little direct effect, though apparently more in the case of
+plants.  Under this point of view, Mr. Buckman's recent experiments on
+plants seem extremely valuable.  When all or nearly all the individuals
+exposed to certain conditions are affected in the same way, the change at
+first appears to be directly due to such conditions; but in some cases it
+can be shown that quite opposite conditions produce similar changes of
+structure.  Nevertheless some slight amount of change may, I think, be
+attributed to the direct action of the conditions of life--as, in some
+cases, increased size from amount of food, colour from particular kinds of
+food and from light, and perhaps the thickness of fur from climate.
+</para>
+
+<para>
+Habit also has a deciding influence, as in the period of flowering with
+plants when transported from one climate to another.  In animals it has a
+more marked effect; for instance, I find in the domestic duck that the
+bones of the wing weigh less and the bones of the leg more, in proportion
+to the whole skeleton, than do the same bones in the wild-duck; and I
+presume that this change may be safely attributed to the domestic duck
+flying much less, and walking more, than its wild parent.  The great and
+inherited development of the udders in cows and goats in countries where
+they are habitually milked, in comparison with the state of these organs in
+other countries, is another instance of the effect of use.  Not a single
+domestic animal can be named which has not in some country drooping ears;
+and the view suggested by some authors, that the drooping is due to the
+disuse of the muscles of the ear, from the animals not being much alarmed
+by danger, seems probable.
+</para>
+
+<para>
+There are many laws regulating variation, some few of which can be dimly
+seen, and will be hereafter briefly mentioned.  I will here only allude to
+what may be called correlation of growth.  Any change in the embryo or
+larva will almost certainly entail changes in the mature animal.  In
+monstrosities, the correlations between quite distinct parts are very
+curious; and many instances are given in Isidore Geoffroy St. Hilaire's
+great work on this subject.  Breeders believe that long limbs are almost
+always accompanied by an elongated head.  Some instances of correlation are
+quite whimsical; thus cats with blue eyes are invariably deaf; colour and
+constitutional peculiarities go together, of which many remarkable cases
+could be given amongst animals and plants.  From the facts collected by
+Heusinger, it appears that white sheep and pigs are differently affected
+from coloured individuals by certain vegetable poisons.  Hairless dogs have
+imperfect teeth; long-haired and coarse-haired animals are apt to have, as
+is asserted, long or many horns; pigeons with feathered feet have skin
+between their outer toes; pigeons with short beaks have small feet, and
+those with long beaks large feet.  Hence, if man goes on selecting, and
+thus augmenting, any peculiarity, he will almost certainly unconsciously
+modify other parts of the structure, owing to the mysterious laws of the
+correlation of growth.
+</para>
+
+<para>
+The result of the various, quite unknown, or dimly seen laws of variation
+is infinitely complex and diversified.  It is well worth while carefully to
+study the several treatises published on some of our old cultivated plants,
+as on the hyacinth, potato, even the dahlia, &amp;c.; and it is really
+surprising to note the endless points in structure and constitution in
+which the varieties and sub-varieties differ slightly from each other.  The
+whole organisation seems to have become plastic, and tends to depart in
+some small degree from that of the parental type.
+</para>
+
+<para>
+Any variation which is not inherited is unimportant for us.  But the number
+and diversity of inheritable deviations of structure, both those of slight
+and those of considerable physiological importance, is endless.  Dr.
+Prosper Lucas's treatise, in two large volumes, is the fullest and the best
+on this subject.  No breeder doubts how strong is the tendency to
+inheritance:  like produces like is his fundamental belief:  doubts have
+been thrown on this principle by theoretical writers alone.  When a
+deviation appears not unfrequently, and we see it in the father and child,
+we cannot tell whether it may not be due to the same original cause acting
+on both; but when amongst individuals, apparently exposed to the same
+conditions, any very rare deviation, due to some extraordinary combination
+of circumstances, appears in the parent--say, once amongst several million
+individuals--and it reappears in the child, the mere doctrine of chances
+almost compels us to attribute its reappearance to inheritance.  Every one
+must have heard of cases of albinism, prickly skin, hairy bodies, &amp;c.,
+appearing in several members of the same family.  If strange and rare
+deviations of structure are truly inherited, less strange and commoner
+deviations may be freely admitted to be inheritable.  Perhaps the correct
+way of viewing the whole subject, would be, to look at the inheritance of
+every character whatever as the rule, and non-inheritance as the anomaly.
+</para>
+
+<para>
+The laws governing inheritance are quite unknown; no one can say why the
+same peculiarity in different individuals of the same species, and in
+individuals of different species, is sometimes inherited and sometimes not
+so; why the child often reverts in certain characters to its grandfather or
+grandmother or other much more remote ancestor; why a peculiarity is often
+transmitted from one sex to both sexes or to one sex alone, more commonly
+but not exclusively to the like sex.  It is a fact of some little
+importance to us, that peculiarities appearing in the males of our domestic
+breeds are often transmitted either exclusively, or in a much greater
+degree, to males alone.  A much more important rule, which I think may be
+trusted, is that, at whatever period of life a peculiarity first appears,
+it tends to appear in the offspring at a corresponding age, though
+sometimes earlier.  In many cases this could not be otherwise:  thus the
+inherited peculiarities in the horns of cattle could appear only in the
+offspring when nearly mature; peculiarities in the silkworm are known to
+appear at the corresponding caterpillar or cocoon stage.  But hereditary
+diseases and some other facts make me believe that the rule has a wider
+extension, and that when there is no apparent reason why a peculiarity
+should appear at any particular age, yet that it does tend to appear in the
+offspring at the same period at which it first appeared in the parent.  I
+believe this rule to be of the highest importance in explaining the laws of
+embryology.  These remarks are of course confined to the first appearance
+of the peculiarity, and not to its primary cause, which may have acted on
+the ovules or male element; in nearly the same manner as in the crossed
+offspring from a short-horned cow by a long-horned bull, the greater length
+of horn, though appearing late in life, is clearly due to the male element.
+</para>
+
+<para>
+Having alluded to the subject of reversion, I may here refer to a statement
+often made by naturalists--namely, that our domestic varieties, when run
+wild, gradually but certainly revert in character to their aboriginal
+stocks.  Hence it has been argued that no deductions can be drawn from
+domestic races to species in a state of nature.  I have in vain endeavoured
+to discover on what decisive facts the above statement has so often and so
+boldly been made.  There would be great difficulty in proving its truth: 
+we may safely conclude that very many of the most strongly-marked domestic
+varieties could not possibly live in a wild state.  In many cases we do not
+know what the aboriginal stock was, and so could not tell whether or not
+nearly perfect reversion had ensued.  It would be quite necessary, in order
+to prevent the effects of intercrossing, that only a single variety should
+be turned loose in its new home.  Nevertheless, as our varieties certainly
+do occasionally revert in some of their characters to ancestral forms, it
+seems to me not improbable, that if we could succeed in naturalising, or
+were to cultivate, during many generations, the several races, for
+instance, of the cabbage, in very poor soil (in which case, however, some
+effect would have to be attributed to the direct action of the poor soil),
+that they would to a large extent, or even wholly, revert to the wild
+aboriginal stock.  Whether or not the experiment would succeed, is not of
+great importance for our line of argument; for by the experiment itself the
+conditions of life are changed.  If it could be shown that our domestic
+varieties manifested a strong tendency to reversion,--that is, to lose
+their acquired characters, whilst kept under unchanged conditions, and
+whilst kept in a considerable body, so that free intercrossing might check,
+by blending together, any slight deviations of structure, in such case, I
+grant that we could deduce nothing from domestic varieties in regard to
+species.  But there is not a shadow of evidence in favour of this view:  to
+assert that we could not breed our cart and race-horses, long and
+short-horned cattle, and poultry of various breeds, and esculent
+vegetables, for an almost infinite number of generations, would be opposed
+to all experience.  I may add, that when under nature the conditions of
+life do change, variations and reversions of character probably do occur;
+but natural selection, as will hereafter be explained, will determine how
+far the new characters thus arising shall be preserved.
+</para>
+
+<para>
+When we look to the hereditary varieties or races of our domestic animals
+and plants, and compare them with species closely allied together, we
+generally perceive in each domestic race, as already remarked, less
+uniformity of character than in true species.  Domestic races of the same
+species, also, often have a somewhat monstrous character; by which I mean,
+that, although differing from each other, and from the other species of the
+same genus, in several trifling respects, they often differ in an extreme
+degree in some one part, both when compared one with another, and more
+especially when compared with all the species in nature to which they are
+nearest allied.  With these exceptions (and with that of the perfect
+fertility of varieties when crossed,--a subject hereafter to be discussed),
+domestic races of the same species differ from each other in the same
+manner as, only in most cases in a lesser degree than, do closely-allied
+species of the same genus in a state of nature.  I think this must be
+admitted, when we find that there are hardly any domestic races, either
+amongst animals or plants, which have not been ranked by some competent
+judges as mere varieties, and by other competent judges as the descendants
+of aboriginally distinct species.  If any marked distinction existed
+between domestic races and species, this source of doubt could not so
+perpetually recur.  It has often been stated that domestic races do not
+differ from each other in characters of generic value.  I think it could be
+shown that this statement is hardly correct; but naturalists differ most
+widely in determining what characters are of generic value; all such
+valuations being at present empirical.  Moreover, on the view of the origin
+of genera which I shall presently give, we have no right to expect often to
+meet with generic differences in our domesticated productions.
+</para>
+
+<para>
+When we attempt to estimate the amount of structural difference between the
+domestic races of the same species, we are soon involved in doubt, from not
+knowing whether they have descended from one or several parent-species. 
+This point, if it could be cleared up, would be interesting; if, for
+instance, it could be shown that the greyhound, bloodhound, terrier,
+spaniel, and bull-dog, which we all know propagate their kind so truly,
+were the offspring of any single species, then such facts would have great
+weight in making us doubt about the immutability of the many very closely
+allied and natural species--for instance, of the many foxes--inhabiting
+different quarters of the world.  I do not believe, as we shall presently
+see, that all our dogs have descended from any one wild species; but, in
+the case of some other domestic races, there is presumptive, or even
+strong, evidence in favour of this view.
+</para>
+
+<para>
+It has often been assumed that man has chosen for domestication animals and
+plants having an extraordinary inherent tendency to vary, and likewise to
+withstand diverse climates.  I do not dispute that these capacities have
+added largely to the value of most of our domesticated productions; but how
+could a savage possibly know, when he first tamed an animal, whether it
+would vary in succeeding generations, and whether it would endure other
+climates?  Has the little variability of the ass or guinea-fowl, or the
+small power of endurance of warmth by the rein-deer, or of cold by the
+common camel, prevented their domestication?  I cannot doubt that if other
+animals and plants, equal in number to our domesticated productions, and
+belonging to equally diverse classes and countries, were taken from a state
+of nature, and could be made to breed for an equal number of generations
+under domestication, they would vary on an average as largely as the parent
+species of our existing domesticated productions have varied.
+</para>
+
+<para>
+In the case of most of our anciently domesticated animals and plants, I do
+not think it is possible to come to any definite conclusion, whether they
+have descended from one or several species.  The argument mainly relied on
+by those who believe in the multiple origin of our domestic animals is,
+that we find in the most ancient records, more especially on the monuments
+of Egypt, much diversity in the breeds; and that some of the breeds closely
+resemble, perhaps are identical with, those still existing.  Even if this
+latter fact were found more strictly and generally true than seems to me to
+be the case, what does it show, but that some of our breeds originated
+there, four or five thousand years ago?  But Mr. Horner's researches have
+rendered it in some degree probable that man sufficiently civilized to have
+manufactured pottery existed in the valley of the Nile thirteen or fourteen
+thousand years ago; and who will pretend to say how long before these
+ancient periods, savages, like those of Tierra del Fuego or Australia, who
+possess a semi-domestic dog, may not have existed in Egypt?
+</para>
+
+<para>
+The whole subject must, I think, remain vague; nevertheless, I may, without
+here entering on any details, state that, from geographical and other
+considerations, I think it highly probable that our domestic dogs have
+descended from several wild species.  In regard to sheep and goats I can
+form no opinion.  I should think, from facts communicated to me by Mr.
+Blyth, on the habits, voice, and constitution, &amp;c., of the humped Indian
+cattle, that these had descended from a different aboriginal stock from our
+European cattle; and several competent judges believe that these latter
+have had more than one wild parent.  With respect to horses, from reasons
+which I cannot give here, I am doubtfully inclined to believe, in
+opposition to several authors, that all the races have descended from one
+wild stock.  Mr. Blyth, whose opinion, from his large and varied stores of
+knowledge, I should value more than that of almost any one, thinks that all
+the breeds of poultry have proceeded from the common wild Indian fowl
+(Gallus bankiva).  In regard to ducks and rabbits, the breeds of which
+differ considerably from each other in structure, I do not doubt that they
+all have descended from the common wild duck and rabbit.
+</para>
+
+<para>
+The doctrine of the origin of our several domestic races from several
+aboriginal stocks, has been carried to an absurd extreme by some authors. 
+They believe that every race which breeds true, let the distinctive
+characters be ever so slight, has had its wild prototype.  At this rate
+there must have existed at least a score of species of wild cattle, as many
+sheep, and several goats in Europe alone, and several even within Great
+Britain.  One author believes that there formerly existed in Great Britain
+eleven wild species of sheep peculiar to it!  When we bear in mind that
+Britain has now hardly one peculiar mammal, and France but few distinct
+from those of Germany and conversely, and so with Hungary, Spain, &amp;c., but
+that each of these kingdoms possesses several peculiar breeds of cattle,
+sheep, &amp;c., we must admit that many domestic breeds have originated in
+Europe; for whence could they have been derived, as these several countries
+do not possess a number of peculiar species as distinct parent-stocks?  So
+it is in India.  Even in the case of the domestic dogs of the whole world,
+which I fully admit have probably descended from several wild species, I
+cannot doubt that there has been an immense amount of inherited variation. 
+Who can believe that animals closely resembling the Italian greyhound, the
+bloodhound, the bull-dog, or Blenheim spaniel, &amp;c.--so unlike all wild
+Canidae--ever existed freely in a state of nature?  It has often been
+loosely said that all our races of dogs have been produced by the crossing
+of a few aboriginal species; but by crossing we can get only forms in some
+degree intermediate between their parents; and if we account for our
+several domestic races by this process, we must admit the former existence
+of the most extreme forms, as the Italian greyhound, bloodhound, bull-dog,
+&amp;c., in the wild state.  Moreover, the possibility of making distinct races
+by crossing has been greatly exaggerated.  There can be no doubt that a
+race may be modified by occasional crosses, if aided by the careful
+selection of those individual mongrels, which present any desired
+character; but that a race could be obtained nearly intermediate between
+two extremely different races or species, I can hardly believe.  Sir J.
+Sebright expressly experimentised for this object, and failed.  The
+offspring from the first cross between two pure breeds is tolerably and
+sometimes (as I have found with pigeons) extremely uniform, and everything
+seems simple enough; but when these mongrels are crossed one with another
+for several generations, hardly two of them will be alike, and then the
+extreme difficulty, or rather utter hopelessness, of the task becomes
+apparent.  Certainly, a breed intermediate between two very distinct breeds
+could not be got without extreme care and long-continued selection; nor can
+I find a single case on record of a permanent race having been thus formed.
+</para>
+
+<para>
+On the Breeds of the Domestic Pigeon. -- Believing that it is always best
+to study some special group, I have, after deliberation, taken up domestic
+pigeons.  I have kept every breed which I could purchase or obtain, and
+have been most kindly favoured with skins from several quarters of the
+world, more especially by the Hon. W. Elliot from India, and by the Hon. C.
+Murray from Persia.  Many treatises in different languages have been
+published on pigeons, and some of them are very important, as being of
+considerably antiquity.  I have associated with several eminent fanciers,
+and have been permitted to join two of the London Pigeon Clubs.  The
+diversity of the breeds is something astonishing.  Compare the English
+carrier and the short-faced tumbler, and see the wonderful difference in
+their beaks, entailing corresponding differences in their skulls.  The
+carrier, more especially the male bird, is also remarkable from the
+wonderful development of the carunculated skin about the head, and this is
+accompanied by greatly elongated eyelids, very large external orifices to
+the nostrils, and a wide gape of mouth.  The short-faced tumbler has a beak
+in outline almost like that of a finch; and the common tumbler has the
+singular and strictly inherited habit of flying at a great height in a
+compact flock, and tumbling in the air head over heels.  The runt is a bird
+of great size, with long, massive beak and large feet; some of the
+sub-breeds of runts have very long necks, others very long wings and tails,
+others singularly short tails.  The barb is allied to the carrier, but,
+instead of a very long beak, has a very short and very broad one.  The
+pouter has a much elongated body, wings, and legs; and its enormously
+developed crop, which it glories in inflating, may well excite astonishment
+and even laughter.  The turbit has a very short and conical beak, with a
+line of reversed feathers down the breast; and it has the habit of
+continually expanding slightly the upper part of the oesophagus.  The
+Jacobin has the feathers so much reversed along the back of the neck that
+they form a hood, and it has, proportionally to its size, much elongated
+wing and tail feathers.  The trumpeter and laugher, as their names express,
+utter a very different coo from the other breeds.  The fantail has thirty
+or even forty tail-feathers, instead of twelve or fourteen, the normal
+number in all members of the great pigeon family; and these feathers are
+kept expanded, and are carried so erect that in good birds the head and
+tail touch; the oil-gland is quite aborted.  Several other less distinct
+breeds might have been specified.
+</para>
+
+<para>
+In the skeletons of the several breeds, the development of the bones of the
+face in length and breadth and curvature differs enormously.  The shape, as
+well as the breadth and length of the ramus of the lower jaw, varies in a
+highly remarkable manner.  The number of the caudal and sacral vertebrae
+vary; as does the number of the ribs, together with their relative breadth
+and the presence of processes.  The size and shape of the apertures in the
+sternum are highly variable; so is the degree of divergence and relative
+size of the two arms of the furcula.  The proportional width of the gape of
+mouth, the proportional length of the eyelids, of the orifice of the
+nostrils, of the tongue (not always in strict correlation with the length
+of beak), the size of the crop and of the upper part of the oesophagus; the
+development and abortion of the oil-gland; the number of the primary wing
+and caudal feathers; the relative length of wing and tail to each other and
+to the body; the relative length of leg and of the feet; the number of
+scutellae on the toes, the development of skin between the toes, are all
+points of structure which are variable.  The period at which the perfect
+plumage is acquired varies, as does the state of the down with which the
+nestling birds are clothed when hatched.  The shape and size of the eggs
+vary.  The manner of flight differs remarkably; as does in some breeds the
+voice and disposition.  Lastly, in certain breeds, the males and females
+have come to differ to a slight degree from each other.
+</para>
+
+<para>
+Altogether at least a score of pigeons might be chosen, which if shown to
+an ornithologist, and he were told that they were wild birds, would
+certainly, I think, be ranked by him as well-defined species.  Moreover, I
+do not believe that any ornithologist would place the English carrier, the
+short-faced tumbler, the runt, the barb, pouter, and fantail in the same
+genus; more especially as in each of these breeds several truly-inherited
+sub-breeds, or species as he might have called them, could be shown him.
+</para>
+
+<para>
+Great as the differences are between the breeds of pigeons, I am fully
+convinced that the common opinion of naturalists is correct, namely, that
+all have descended from the rock-pigeon (Columba livia), including under
+this term several geographical races or sub-species, which differ from each
+other in the most trifling respects.  As several of the reasons which have
+led me to this belief are in some degree applicable in other cases, I will
+here briefly give them.  If the several breeds are not varieties, and have
+not proceeded from the rock-pigeon, they must have descended from at least
+seven or eight aboriginal stocks; for it is impossible to make the present
+domestic breeds by the crossing of any lesser number:  how, for instance,
+could a pouter be produced by crossing two breeds unless one of the
+parent-stocks possessed the characteristic enormous crop?  The supposed
+aboriginal stocks must all have been rock-pigeons, that is, not breeding or
+willingly perching on trees.  But besides C. livia, with its geographical
+sub-species, only two or three other species of rock-pigeons are known; and
+these have not any of the characters of the domestic breeds.  Hence the
+supposed aboriginal stocks must either still exist in the countries where
+they were originally domesticated, and yet be unknown to ornithologists;
+and this, considering their size, habits, and remarkable characters, seems
+very improbable; or they must have become extinct in the wild state.  But
+birds breeding on precipices, and good fliers, are unlikely to be
+exterminated; and the common rock-pigeon, which has the same habits with
+the domestic breeds, has not been exterminated even on several of the
+smaller British islets, or on the shores of the Mediterranean.  Hence the
+supposed extermination of so many species having similar habits with the
+rock-pigeon seems to me a very rash assumption.  Moreover, the several
+above-named domesticated breeds have been transported to all parts of the
+world, and, therefore, some of them must have been carried back again into
+their native country; but not one has ever become wild or feral, though the
+dovecot-pigeon, which is the rock-pigeon in a very slightly altered state,
+has become feral in several places.  Again, all recent experience shows
+that it is most difficult to get any wild animal to breed freely under
+domestication; yet on the hypothesis of the multiple origin of our pigeons,
+it must be assumed that at least seven or eight species were so thoroughly
+domesticated in ancient times by half-civilized man, as to be quite
+prolific under confinement.
+</para>
+
+<para>
+An argument, as it seems to me, of great weight, and applicable in several
+other cases, is, that the above-specified breeds, though agreeing generally
+in constitution, habits, voice, colouring, and in most parts of their
+structure, with the wild rock-pigeon, yet are certainly highly abnormal in
+other parts of their structure:  we may look in vain throughout the whole
+great family of Columbidae for a beak like that of the English carrier, or
+that of the short-faced tumbler, or barb; for reversed feathers like those
+of the jacobin; for a crop like that of the pouter; for tail-feathers like
+those of the fantail.  Hence it must be assumed not only that
+half-civilized man succeeded in thoroughly domesticating several species,
+but that he intentionally or by chance picked out extraordinarily abnormal
+species; and further, that these very species have since all become extinct
+or unknown.  So many strange contingencies seem to me improbable in the
+highest degree.
+</para>
+
+<para>
+Some facts in regard to the colouring of pigeons well deserve
+consideration.  The rock-pigeon is of a slaty-blue, and has a white rump
+(the Indian sub-species, C. intermedia of Strickland, having it bluish);
+the tail has a terminal dark bar, with the bases of the outer feathers
+externally edged with white; the wings have two black bars; some
+semi-domestic breeds and some apparently truly wild breeds have, besides
+the two black bars, the wings chequered with black.  These several marks do
+not occur together in any other species of the whole family.  Now, in every
+one of the domestic breeds, taking thoroughly well-bred birds, all the
+above marks, even to the white edging of the outer tail-feathers, sometimes
+concur perfectly developed.  Moreover, when two birds belonging to two
+distinct breeds are crossed, neither of which is blue or has any of the
+above-specified marks, the mongrel offspring are very apt suddenly to
+acquire these characters; for instance, I crossed some uniformly white
+fantails with some uniformly black barbs, and they produced mottled brown
+and black birds; these I again crossed together, and one grandchild of the
+pure white fantail and pure black barb was of as beautiful a blue colour,
+with the white rump, double black wing-bar, and barred and white-edged
+tail-feathers, as any wild rock-pigeon!  We can understand these facts, on
+the well-known principle of reversion to ancestral characters, if all the
+domestic breeds have descended from the rock-pigeon.  But if we deny this,
+we must make one of the two following highly improbable suppositions. 
+Either, firstly, that all the several imagined aboriginal stocks were
+coloured and marked like the rock-pigeon, although no other existing
+species is thus coloured and marked, so that in each separate breed there
+might be a tendency to revert to the very same colours and markings.  Or,
+secondly, that each breed, even the purest, has within a dozen or, at most,
+within a score of generations, been crossed by the rock-pigeon:  I say
+within a dozen or twenty generations, for we know of no fact countenancing
+the belief that the child ever reverts to some one ancestor, removed by a
+greater number of generations.  In a breed which has been crossed only once
+with some distinct breed, the tendency to reversion to any character
+derived from such cross will naturally become less and less, as in each
+succeeding generation there will be less of the foreign blood; but when
+there has been no cross with a distinct breed, and there is a tendency in
+both parents to revert to a character, which has been lost during some
+former generation, this tendency, for all that we can see to the contrary,
+may be transmitted undiminished for an indefinite number of generations. 
+These two distinct cases are often confounded in treatises on inheritance.
+</para>
+
+<para>
+Lastly, the hybrids or mongrels from between all the domestic breeds of
+pigeons are perfectly fertile.  I can state this from my own observations,
+purposely made on the most distinct breeds.  Now, it is difficult, perhaps
+impossible, to bring forward one case of the hybrid offspring of two
+animals clearly distinct being themselves perfectly fertile.  Some authors
+believe that long-continued domestication eliminates this strong tendency
+to sterility:  from the history of the dog I think there is some
+probability in this hypothesis, if applied to species closely related
+together, though it is unsupported by a single experiment.  But to extend
+the hypothesis so far as to suppose that species, aboriginally as distinct
+as carriers, tumblers, pouters, and fantails now are, should yield
+offspring perfectly fertile, inter se, seems to me rash in the extreme.
+</para>
+
+<para>
+From these several reasons, namely, the improbability of man having
+formerly got seven or eight supposed species of pigeons to breed freely
+under domestication; these supposed species being quite unknown in a wild
+state, and their becoming nowhere feral; these species having very abnormal
+characters in certain respects, as compared with all other Columbidae,
+though so like in most other respects to the rock-pigeon; the blue colour
+and various marks occasionally appearing in all the breeds, both when kept
+pure and when crossed; the mongrel offspring being perfectly fertile;--from
+these several reasons, taken together, I can feel no doubt that all our
+domestic breeds have descended from the Columba livia with its geographical
+sub-species.
+</para>
+
+<para>
+In favour of this view, I may add, firstly, that C. livia, or the
+rock-pigeon, has been found capable of domestication in Europe and in
+India; and that it agrees in habits and in a great number of points of
+structure with all the domestic breeds.  Secondly, although an English
+carrier or short-faced tumbler differs immensely in certain characters from
+the rock-pigeon, yet by comparing the several sub-breeds of these breeds,
+more especially those brought from distant countries, we can make an almost
+perfect series between the extremes of structure.  Thirdly, those
+characters which are mainly distinctive of each breed, for instance the
+wattle and length of beak of the carrier, the shortness of that of the
+tumbler, and the number of tail-feathers in the fantail, are in each breed
+eminently variable; and the explanation of this fact will be obvious when
+we come to treat of selection.  Fourthly, pigeons have been watched, and
+tended with the utmost care, and loved by many people.  They have been
+domesticated for thousands of years in several quarters of the world; the
+earliest known record of pigeons is in the fifth Aegyptian dynasty, about
+3000 B.C., as was pointed out to me by Professor Lepsius; but Mr. Birch
+informs me that pigeons are given in a bill of fare in the previous
+dynasty.  In the time of the Romans, as we hear from Pliny, immense prices
+were given for pigeons; 'nay, they are come to this pass, that they can
+reckon up their pedigree and race.'  Pigeons were much valued by Akber Khan
+in India, about the year 1600; never less than 20,000 pigeons were taken
+with the court.  'The monarchs of Iran and Turan sent him some very rare
+birds;' and, continues the courtly historian, 'His Majesty by crossing the
+breeds, which method was never practised before, has improved them
+astonishingly.'  About this same period the Dutch were as eager about
+pigeons as were the old Romans.  The paramount importance of these
+considerations in explaining the immense amount of variation which pigeons
+have undergone, will be obvious when we treat of Selection.  We shall then,
+also, see how it is that the breeds so often have a somewhat monstrous
+character.  It is also a most favourable circumstance for the production of
+distinct breeds, that male and female pigeons can be easily mated for life;
+and thus different breeds can be kept together in the same aviary.
+</para>
+
+<para>
+I have discussed the probable origin of domestic pigeons at some, yet quite
+insufficient, length; because when I first kept pigeons and watched the
+several kinds, knowing well how true they bred, I felt fully as much
+difficulty in believing that they could ever have descended from a common
+parent, as any naturalist could in coming to a similar conclusion in regard
+to the many species of finches, or other large groups of birds, in nature. 
+One circumstance has struck me much; namely, that all the breeders of the
+various domestic animals and the cultivators of plants, with whom I have
+ever conversed, or whose treatises I have read, are firmly convinced that
+the several breeds to which each has attended, are descended from so many
+aboriginally distinct species.  Ask, as I have asked, a celebrated raiser
+of Hereford cattle, whether his cattle might not have descended from long
+horns, and he will laugh you to scorn.  I have never met a pigeon, or
+poultry, or duck, or rabbit fancier, who was not fully convinced that each
+main breed was descended from a distinct species.  Van Mons, in his
+treatise on pears and apples, shows how utterly he disbelieves that the
+several sorts, for instance a Ribston-pippin or Codlin-apple, could ever
+have proceeded from the seeds of the same tree.  Innumerable other examples
+could be given.  The explanation, I think, is simple:  from long-continued
+study they are strongly impressed with the differences between the several
+races; and though they well know that each race varies slightly, for they
+win their prizes by selecting such slight differences, yet they ignore all
+general arguments, and refuse to sum up in their minds slight differences
+accumulated during many successive generations.  May not those naturalists
+who, knowing far less of the laws of inheritance than does the breeder, and
+knowing no more than he does of the intermediate links in the long lines of
+descent, yet admit that many of our domestic races have descended from the
+same parents--may they not learn a lesson of caution, when they deride the
+idea of species in a state of nature being lineal descendants of other
+species?
+</para>
+
+<para>
+
+Selection. -- Let us now briefly consider the steps by which domestic races
+have been produced, either from one or from several allied species.  Some
+little effect may, perhaps, be attributed to the direct action of the
+external conditions of life, and some little to habit; but he would be a
+bold man who would account by such agencies for the differences of a dray
+and race horse, a greyhound and bloodhound, a carrier and tumbler pigeon. 
+One of the most remarkable features in our domesticated races is that we
+see in them adaptation, not indeed to the animal's or plant's own good, but
+to man's use or fancy.  Some variations useful to him have probably arisen
+suddenly, or by one step; many botanists, for instance, believe that the
+fuller's teazle, with its hooks, which cannot be rivalled by any mechanical
+contrivance, is only a variety of the wild Dipsacus; and this amount of
+change may have suddenly arisen in a seedling.  So it has probably been
+with the turnspit dog; and this is known to have been the case with the
+ancon sheep.  But when we compare the dray-horse and race-horse, the
+dromedary and camel, the various breeds of sheep fitted either for
+cultivated land or mountain pasture, with the wool of one breed good for
+one purpose, and that of another breed for another purpose; when we compare
+the many breeds of dogs, each good for man in very different ways; when we
+compare the game-cock, so pertinacious in battle, with other breeds so
+little quarrelsome, with 'everlasting layers' which never desire to sit,
+and with the bantam so small and elegant; when we compare the host of
+agricultural, culinary, orchard, and flower-garden races of plants, most
+useful to man at different seasons and for different purposes, or so
+beautiful in his eyes, we must, I think, look further than to mere
+variability.  We cannot suppose that all the breeds were suddenly produced
+as perfect and as useful as we now see them; indeed, in several cases, we
+know that this has not been their history.  The key is man's power of
+accumulative selection:  nature gives successive variations; man adds them
+up in certain directions useful to him.  In this sense he may be said to
+make for himself useful breeds.
+</para>
+
+<para>
+The great power of this principle of selection is not hypothetical.  It is
+certain that several of our eminent breeders have, even within a single
+lifetime, modified to a large extent some breeds of cattle and sheep.  In
+order fully to realise what they have done, it is almost necessary to read
+several of the many treatises devoted to this subject, and to inspect the
+animals.  Breeders habitually speak of an animal's organisation as
+something quite plastic, which they can model almost as they please.  If I
+had space I could quote numerous passages to this effect from highly
+competent authorities.  Youatt, who was probably better acquainted with the
+works of agriculturalists than almost any other individual, and who was
+himself a very good judge of an animal, speaks of the principle of
+selection as 'that which enables the agriculturist, not only to modify the
+character of his flock, but to change it altogether.  It is the magician's
+wand, by means of which he may summon into life whatever form and mould he
+pleases.'  Lord Somerville, speaking of what breeders have done for sheep,
+says:- 'It would seem as if they had chalked out upon a wall a form perfect
+in itself, and then had given it existence.'  That most skilful breeder,
+Sir John Sebright, used to say, with respect to pigeons, that 'he would
+produce any given feather in three years, but it would take him six years
+to obtain head and beak.'  In Saxony the importance of the principle of
+selection in regard to merino sheep is so fully recognised, that men follow
+it as a trade:  the sheep are placed on a table and are studied, like a
+picture by a connoisseur; this is done three times at intervals of months,
+and the sheep are each time marked and classed, so that the very best may
+ultimately be selected for breeding.
+</para>
+
+<para>
+What English breeders have actually effected is proved by the enormous
+prices given for animals with a good pedigree; and these have now been
+exported to almost every quarter of the world.  The improvement is by no
+means generally due to crossing different breeds; all the best breeders are
+strongly opposed to this practice, except sometimes amongst closely allied
+sub-breeds.  And when a cross has been made, the closest selection is far
+more indispensable even than in ordinary cases.  If selection consisted
+merely in separating some very distinct variety, and breeding from it, the
+principle would be so obvious as hardly to be worth notice; but its
+importance consists in the great effect produced by the accumulation in one
+direction, during successive generations, of differences absolutely
+inappreciable by an uneducated eye--differences which I for one have vainly
+attempted to appreciate.  Not one man in a thousand has accuracy of eye and
+judgment sufficient to become an eminent breeder.  If gifted with these
+qualities, and he studies his subject for years, and devotes his lifetime
+to it with indomitable perseverance, he will succeed, and may make great
+improvements; if he wants any of these qualities, he will assuredly fail. 
+Few would readily believe in the natural capacity and years of practice
+requisite to become even a skilful pigeon-fancier.
+</para>
+
+<para>
+The same principles are followed by horticulturists; but the variations are
+here often more abrupt.  No one supposes that our choicest productions have
+been produced by a single variation from the aboriginal stock.  We have
+proofs that this is not so in some cases, in which exact records have been
+kept; thus, to give a very trifling instance, the steadily-increasing size
+of the common gooseberry may be quoted.  We see an astonishing improvement
+in many florists' flowers, when the flowers of the present day are compared
+with drawings made only twenty or thirty years ago.  When a race of plants
+is once pretty well established, the seed-raisers do not pick out the best
+plants, but merely go over their seed-beds, and pull up the 'rogues,' as
+they call the plants that deviate from the proper standard.  With animals
+this kind of selection is, in fact, also followed; for hardly any one is so
+careless as to allow his worst animals to breed.
+</para>
+
+<para>
+In regard to plants, there is another means of observing the accumulated
+effects of selection--namely, by comparing the diversity of flowers in the
+different varieties of the same species in the flower-garden; the diversity
+of leaves, pods, or tubers, or whatever part is valued, in the
+kitchen-garden, in comparison with the flowers of the same varieties; and
+the diversity of fruit of the same species in the orchard, in comparison
+with the leaves and flowers of the same set of varieties.  See how
+different the leaves of the cabbage are, and how extremely alike the
+flowers; how unlike the flowers of the heartsease are, and how alike the
+leaves; how much the fruit of the different kinds of gooseberries differ in
+size, colour, shape, and hairiness, and yet the flowers present very slight
+differences.  It is not that the varieties which differ largely in some one
+point do not differ at all in other points; this is hardly ever, perhaps
+never, the case.  The laws of correlation of growth, the importance of
+which should never be overlooked, will ensure some differences; but, as a
+general rule, I cannot doubt that the continued selection of slight
+variations, either in the leaves, the flowers, or the fruit, will produce
+races differing from each other chiefly in these characters.
+</para>
+
+<para>
+It may be objected that the principle of selection has been reduced to
+methodical practice for scarcely more than three-quarters of a century; it
+has certainly been more attended to of late years, and many treatises have
+been published on the subject; and the result, I may add, has been, in a
+corresponding degree, rapid and important.  But it is very far from true
+that the principle is a modern discovery.  I could give several references
+to the full acknowledgment of the importance of the principle in works of
+high antiquity.  In rude and barbarous periods of English history choice
+animals were often imported, and laws were passed to prevent their
+exportation:  the destruction of horses under a certain size was ordered,
+and this may be compared to the 'roguing' of plants by nurserymen.  The
+principle of selection I find distinctly given in an ancient Chinese
+encyclopaedia.  Explicit rules are laid down by some of the Roman classical
+writers.  From passages in Genesis, it is clear that the colour of domestic
+animals was at that early period attended to.  Savages now sometimes cross
+their dogs with wild canine animals, to improve the breed, and they
+formerly did so, as is attested by passages in Pliny.  The savages in South
+Africa match their draught cattle by colour, as do some of the Esquimaux
+their teams of dogs.  Livingstone shows how much good domestic breeds are
+valued by the negroes of the interior of Africa who have not associated
+with Europeans.  Some of these facts do not show actual selection, but they
+show that the breeding of domestic animals was carefully attended to in
+ancient times, and is now attended to by the lowest savages.  It would,
+indeed, have been a strange fact, had attention not been paid to breeding,
+for the inheritance of good and bad qualities is so obvious.
+</para>
+
+<para>
+At the present time, eminent breeders try by methodical selection, with a
+distinct object in view, to make a new strain or sub-breed, superior to
+anything existing in the country.  But, for our purpose, a kind of
+Selection, which may be called Unconscious, and which results from every
+one trying to possess and breed from the best individual animals, is more
+important.  Thus, a man who intends keeping pointers naturally tries to get
+as good dogs as he can, and afterwards breeds from his own best dogs, but
+he has no wish or expectation of permanently altering the breed. 
+Nevertheless I cannot doubt that this process, continued during centuries,
+would improve and modify any breed, in the same way as Bakewell, Collins,
+&amp;c., by this very same process, only carried on more methodically, did
+greatly modify, even during their own lifetimes, the forms and qualities of
+their cattle.  Slow and insensible changes of this kind could never be
+recognised unless actual measurements or careful drawings of the breeds in
+question had been made long ago, which might serve for comparison.  In some
+cases, however, unchanged or but little changed individuals of the same
+breed may be found in less civilised districts, where the breed has been
+less improved.  There is reason to believe that King Charles's spaniel has
+been unconsciously modified to a large extent since the time of that
+monarch.  Some highly competent authorities are convinced that the setter
+is directly derived from the spaniel, and has probably been slowly altered
+from it.  It is known that the English pointer has been greatly changed
+within the last century, and in this case the change has, it is believed,
+been chiefly effected by crosses with the fox-hound; but what concerns us
+is, that the change has been effected unconsciously and gradually, and yet
+so effectually, that, though the old Spanish pointer certainly came from
+Spain, Mr. Borrow has not seen, as I am informed by him, any native dog in
+Spain like our pointer.
+</para>
+
+<para>
+By a similar process of selection, and by careful training, the whole body
+of English racehorses have come to surpass in fleetness and size the parent
+Arab stock, so that the latter, by the regulations for the Goodwood Races,
+are favoured in the weights they carry.  Lord Spencer and others have shown
+how the cattle of England have increased in weight and in early maturity,
+compared with the stock formerly kept in this country.  By comparing the
+accounts given in old pigeon treatises of carriers and tumblers with these
+breeds as now existing in Britain, India, and Persia, we can, I think,
+clearly trace the stages through which they have insensibly passed, and
+come to differ so greatly from the rock-pigeon.
+</para>
+
+<para>
+Youatt gives an excellent illustration of the effects of a course of
+selection, which may be considered as unconsciously followed, in so far
+that the breeders could never have expected or even have wished to have
+produced the result which ensued--namely, the production of two distinct
+strains.  The two flocks of Leicester sheep kept by Mr. Buckley and Mr.
+Burgess, as Mr. Youatt remarks, 'have been purely bred from the original
+stock of Mr. Bakewell for upwards of fifty years.  There is not a suspicion
+existing in the mind of any one at all acquainted with the subject that the
+owner of either of them has deviated in any one instance from the pure
+blood of Mr. Bakewell's flock, and yet the difference between the sheep
+possessed by these two gentlemen is so great that they have the appearance
+of being quite different varieties.'
+</para>
+
+<para>
+If there exist savages so barbarous as never to think of the inherited
+character of the offspring of their domestic animals, yet any one animal
+particularly useful to them, for any special purpose, would be carefully
+preserved during famines and other accidents, to which savages are so
+liable, and such choice animals would thus generally leave more offspring
+than the inferior ones; so that in this case there would be a kind of
+unconscious selection going on.  We see the value set on animals even by
+the barbarians of Tierra del Fuego, by their killing and devouring their
+old women, in times of dearth, as of less value than their dogs.
+</para>
+
+<para>
+In plants the same gradual process of improvement, through the occasional
+preservation of the best individuals, whether or not sufficiently distinct
+to be ranked at their first appearance as distinct varieties, and whether
+or not two or more species or races have become blended together by
+crossing, may plainly be recognised in the increased size and beauty which
+we now see in the varieties of the heartsease, rose, pelargonium, dahlia,
+and other plants, when compared with the older varieties or with their
+parent-stocks.  No one would ever expect to get a first-rate heartsease or
+dahlia from the seed of a wild plant.  No one would expect to raise a
+first-rate melting pear from the seed of a wild pear, though he might
+succeed from a poor seedling growing wild, if it had come from a
+garden-stock.  The pear, though cultivated in classical times, appears,
+from Pliny's description, to have been a fruit of very inferior quality.  I
+have seen great surprise expressed in horticultural works at the wonderful
+skill of gardeners, in having produced such splendid results from such poor
+materials; but the art, I cannot doubt, has been simple, and, as far as the
+final result is concerned, has been followed almost unconsciously.  It has
+consisted in always cultivating the best known variety, sowing its seeds,
+and, when a slightly better variety has chanced to appear, selecting it,
+and so onwards.  But the gardeners of the classical period, who cultivated
+the best pear they could procure, never thought what splendid fruit we
+should eat; though we owe our excellent fruit, in some small degree, to
+their having naturally chosen and preserved the best varieties they could
+anywhere find.
+</para>
+
+<para>
+A large amount of change in our cultivated plants, thus slowly and
+unconsciously accumulated, explains, as I believe, the well-known fact,
+that in a vast number of cases we cannot recognise, and therefore do not
+know, the wild parent-stocks of the plants which have been longest
+cultivated in our flower and kitchen gardens.  If it has taken centuries or
+thousands of years to improve or modify most of our plants up to their
+present standard of usefulness to man, we can understand how it is that
+neither Australia, the Cape of Good Hope, nor any other region inhabited by
+quite uncivilised man, has afforded us a single plant worth culture.  It is
+not that these countries, so rich in species, do not by a strange chance
+possess the aboriginal stocks of any useful plants, but that the native
+plants have not been improved by continued selection up to a standard of
+perfection comparable with that given to the plants in countries anciently
+civilised.
+</para>
+
+<para>
+In regard to the domestic animals kept by uncivilised man, it should not be
+overlooked that they almost always have to struggle for their own food, at
+least during certain seasons.  And in two countries very differently
+circumstanced, individuals of the same species, having slightly different
+constitutions or structure, would often succeed better in the one country
+than in the other, and thus by a process of 'natural selection,' as will
+hereafter be more fully explained, two sub-breeds might be formed.  This,
+perhaps, partly explains what has been remarked by some authors, namely,
+that the varieties kept by savages have more of the character of species
+than the varieties kept in civilised countries.
+</para>
+
+<para>
+On the view here given of the all-important part which selection by man has
+played, it becomes at once obvious, how it is that our domestic races show
+adaptation in their structure or in their habits to man's wants or fancies. 
+We can, I think, further understand the frequently abnormal character of
+our domestic races, and likewise their differences being so great in
+external characters and relatively so slight in internal parts or organs. 
+Man can hardly select, or only with much difficulty, any deviation of
+structure excepting such as is externally visible; and indeed he rarely
+cares for what is internal.  He can never act by selection, excepting on
+variations which are first given to him in some slight degree by nature. 
+No man would ever try to make a fantail, till he saw a pigeon with a tail
+developed in some slight degree in an unusual manner, or a pouter till he
+saw a pigeon with a crop of somewhat unusual size; and the more abnormal or
+unusual any character was when it first appeared, the more likely it would
+be to catch his attention.  But to use such an expression as trying to make
+a fantail, is, I have no doubt, in most cases, utterly incorrect.  The man
+who first selected a pigeon with a slightly larger tail, never dreamed what
+the descendants of that pigeon would become through long-continued, partly
+unconscious and partly methodical selection.  Perhaps the parent bird of
+all fantails had only fourteen tail-feathers somewhat expanded, like the
+present Java fantail, or like individuals of other and distinct breeds, in
+which as many as seventeen tail-feathers have been counted.  Perhaps the
+first pouter-pigeon did not inflate its crop much more than the turbit now
+does the upper part of its oesophagus,--a habit which is disregarded by all
+fanciers, as it is not one of the points of the breed.
+</para>
+
+<para>
+Nor let it be thought that some great deviation of structure would be
+necessary to catch the fancier's eye:  he perceives extremely small
+differences, and it is in human nature to value any novelty, however
+slight, in one's own possession.  Nor must the value which would formerly
+be set on any slight differences in the individuals of the same species, be
+judged of by the value which would now be set on them, after several breeds
+have once fairly been established.  Many slight differences might, and
+indeed do now, arise amongst pigeons, which are rejected as faults or
+deviations from the standard of perfection of each breed.  The common goose
+has not given rise to any marked varieties; hence the Thoulouse and the
+common breed, which differ only in colour, that most fleeting of
+characters, have lately been exhibited as distinct at our poultry-shows.
+</para>
+
+<para>
+I think these views further explain what has sometimes been noticed--namely
+that we know nothing about the origin or history of any of our domestic
+breeds.  But, in fact, a breed, like a dialect of a language, can hardly be
+said to have had a definite origin.  A man preserves and breeds from an
+individual with some slight deviation of structure, or takes more care than
+usual in matching his best animals and thus improves them, and the improved
+individuals slowly spread in the immediate neighbourhood.  But as yet they
+will hardly have a distinct name, and from being only slightly valued,
+their history will be disregarded.  When further improved by the same slow
+and gradual process, they will spread more widely, and will get recognised
+as something distinct and valuable, and will then probably first receive a
+provincial name.  In semi-civilised countries, with little free
+communication, the spreading and knowledge of any new sub-breed will be a
+slow process.  As soon as the points of value of the new sub-breed are once
+fully acknowledged, the principle, as I have called it, of unconscious
+selection will always tend,--perhaps more at one period than at another, as
+the breed rises or falls in fashion,--perhaps more in one district than in
+another, according to the state of civilisation of the inhabitants--slowly
+to add to the characteristic features of the breed, whatever they may be. 
+But the chance will be infinitely small of any record having been preserved
+of such slow, varying, and insensible changes.
+</para>
+
+<para>
+I must now say a few words on the circumstances, favourable, or the
+reverse, to man's power of selection.  A high degree of variability is
+obviously favourable, as freely giving the materials for selection to work
+on; not that mere individual differences are not amply sufficient, with
+extreme care, to allow of the accumulation of a large amount of
+modification in almost any desired direction.  But as variations manifestly
+useful or pleasing to man appear only occasionally, the chance of their
+appearance will be much increased by a large number of individuals being
+kept; and hence this comes to be of the highest importance to success.  On
+this principle Marshall has remarked, with respect to the sheep of parts of
+Yorkshire, that 'as they generally belong to poor people, and are mostly in
+small lots, they never can be improved.'  On the other hand, nurserymen,
+from raising large stocks of the same plants, are generally far more
+successful than amateurs in getting new and valuable varieties.  The
+keeping of a large number of individuals of a species in any country
+requires that the species should be placed under favourable conditions of
+life, so as to breed freely in that country.  When the individuals of any
+species are scanty, all the individuals, whatever their quality may be,
+will generally be allowed to breed, and this will effectually prevent
+selection.  But probably the most important point of all, is, that the
+animal or plant should be so highly useful to man, or so much valued by
+him, that the closest attention should be paid to even the slightest
+deviation in the qualities or structure of each individual.  Unless such
+attention be paid nothing can be effected.  I have seen it gravely
+remarked, that it was most fortunate that the strawberry began to vary just
+when gardeners began to attend closely to this plant.  No doubt the
+strawberry had always varied since it was cultivated, but the slight
+varieties had been neglected.  As soon, however, as gardeners picked out
+individual plants with slightly larger, earlier, or better fruit, and
+raised seedlings from them, and again picked out the best seedlings and
+bred from them, then, there appeared (aided by some crossing with distinct
+species) those many admirable varieties of the strawberry which have been
+raised during the last thirty or forty years.
+</para>
+
+<para>
+In the case of animals with separate sexes, facility in preventing crosses
+is an important element of success in the formation of new races,--at
+least, in a country which is already stocked with other races.  In this
+respect enclosure of the land plays a part.  Wandering savages or the
+inhabitants of open plains rarely possess more than one breed of the same
+species.  Pigeons can be mated for life, and this is a great convenience to
+the fancier, for thus many races may be kept true, though mingled in the
+same aviary; and this circumstance must have largely favoured the
+improvement and formation of new breeds.  Pigeons, I may add, can be
+propagated in great numbers and at a very quick rate, and inferior birds
+may be freely rejected, as when killed they serve for food.  On the other
+hand, cats, from their nocturnal rambling habits, cannot be matched, and,
+although so much valued by women and children, we hardly ever see a
+distinct breed kept up; such breeds as we do sometimes see are almost
+always imported from some other country, often from islands.  Although I do
+not doubt that some domestic animals vary less than others, yet the rarity
+or absence of distinct breeds of the cat, the donkey, peacock, goose, &amp;c.,
+may be attributed in main part to selection not having been brought into
+play:  in cats, from the difficulty in pairing them; in donkeys, from only
+a few being kept by poor people, and little attention paid to their
+breeding; in peacocks, from not being very easily reared and a large stock
+not kept; in geese, from being valuable only for two purposes, food and
+feathers, and more especially from no pleasure having been felt in the
+display of distinct breeds.
+</para>
+
+<para>
+To sum up on the origin of our Domestic Races of animals and plants.  I
+believe that the conditions of life, from their action on the reproductive
+system, are so far of the highest importance as causing variability.  I do
+not believe that variability is an inherent and necessary contingency,
+under all circumstances, with all organic beings, as some authors have
+thought.  The effects of variability are modified by various degrees of
+inheritance and of reversion.  Variability is governed by many unknown
+laws, more especially by that of correlation of growth.  Something may be
+attributed to the direct action of the conditions of life.  Something must
+be attributed to use and disuse.  The final result is thus rendered
+infinitely complex.  In some cases, I do not doubt that the intercrossing
+of species, aboriginally distinct, has played an important part in the
+origin of our domestic productions.  When in any country several domestic
+breeds have once been established, their occasional intercrossing, with the
+aid of selection, has, no doubt, largely aided in the formation of new
+sub-breeds; but the importance of the crossing of varieties has, I believe,
+been greatly exaggerated, both in regard to animals and to those plants
+which are propagated by seed.  In plants which are temporarily propagated
+by cuttings, buds, &amp;c., the importance of the crossing both of distinct
+species and of varieties is immense; for the cultivator here quite
+disregards the extreme variability both of hybrids and mongrels, and the
+frequent sterility of hybrids; but the cases of plants not propagated by
+seed are of little importance to us, for their endurance is only temporary. 
+Over all these causes of Change I am convinced that the accumulative action
+of Selection, whether applied methodically and more quickly, or
+unconsciously and more slowly, but more efficiently, is by far the
+predominant Power.
+</para>
+
+</chapter>
+
+<chapter>
+<chapheader>
+
+<chapnum>Chapter II</chapnum>
+
+<title>Variation Under Nature</title>
+
+<chapsummary>
+Variability -- Individual differences -- Doubtful species -- Wide ranging,
+much diffused, and common species vary most -- Species of the larger genera
+in any country vary more than the species of the smaller genera -- Many of
+the species of the larger genera resemble varieties in being very closely,
+but unequally, related to each other, and in having restricted ranges.
+</chapsummary>
+</chapheader>
+
+<para>
+Before applying the principles arrived at in the last chapter to organic
+beings in a state of nature, we must briefly discuss whether these latter
+are subject to any variation.  To treat this subject at all properly, a
+long catalogue of dry facts should be given; but these I shall reserve for
+my future work.  Nor shall I here discuss the various definitions which
+have been given of the term species.  No one definition has as yet
+satisfied all naturalists; yet every naturalist knows vaguely what he means
+when he speaks of a species.  Generally the term includes the unknown
+element of a distinct act of creation.  The term 'variety' is almost
+equally difficult to define; but here community of descent is almost
+universally implied, though it can rarely be proved.  We have also what are
+called monstrosities; but they graduate into varieties.  By a monstrosity I
+presume is meant some considerable deviation of structure in one part,
+either injurious to or not useful to the species, and not generally
+propagated.  Some authors use the term 'variation' in a technical sense, as
+implying a modification directly due to the physical conditions of life;
+and 'variations' in this sense are supposed not to be inherited:  but who
+can say that the dwarfed condition of shells in the brackish waters of the
+Baltic, or dwarfed plants on Alpine summits, or the thicker fur of an
+animal from far northwards, would not in some cases be inherited for at
+least some few generations? and in this case I presume that the form would
+be called a variety.
+</para>
+
+<para>
+Again, we have many slight differences which may be called individual
+differences, such as are known frequently to appear in the offspring from
+the same parents, or which may be presumed to have thus arisen, from being
+frequently observed in the individuals of the same species inhabiting the
+same confined locality.  No one supposes that all the individuals of the
+same species are cast in the very same mould.  These individual differences
+are highly important for us, as they afford materials for natural selection
+to accumulate, in the same manner as man can accumulate in any given
+direction individual differences in his domesticated productions.  These
+individual differences generally affect what naturalists consider
+unimportant parts; but I could show by a long catalogue of facts, that
+parts which must be called important, whether viewed under a physiological
+or classificatory point of view, sometimes vary in the individuals of the
+same species.  I am convinced that the most experienced naturalist would be
+surprised at the number of the cases of variability, even in important
+parts of structure, which he could collect on good authority, as I have
+collected, during a course of years.  It should be remembered that
+systematists are far from pleased at finding variability in important
+characters, and that there are not many men who will laboriously examine
+internal and important organs, and compare them in many specimens of the
+same species.  I should never have expected that the branching of the main
+nerves close to the great central ganglion of an insect would have been
+variable in the same species; I should have expected that changes of this
+nature could have been effected only by slow degrees:  yet quite recently
+Mr. Lubbock has shown a degree of variability in these main nerves in
+Coccus, which may almost be compared to the irregular branching of the stem
+of a tree.  This philosophical naturalist, I may add, has also quite
+recently shown that the muscles in the larvae of certain insects are very
+far from uniform.  Authors sometimes argue in a circle when they state that
+important organs never vary; for these same authors practically rank that
+character as important (as some few naturalists have honestly confessed)
+which does not vary; and, under this point of view, no instance of any
+important part varying will ever be found:  but under any other point of
+view many instances assuredly can be given.
+</para>
+
+<para>
+There is one point connected with individual differences, which seems to me
+extremely perplexing:  I refer to those genera which have sometimes been
+called 'protean' or 'polymorphic,' in which the species present an
+inordinate amount of variation; and hardly two naturalists can agree which
+forms to rank as species and which as varieties.  We may instance Rubus,
+Rosa, and Hieracium amongst plants, several genera of insects, and several
+genera of Brachiopod shells.  In most polymorphic genera some of the
+species have fixed and definite characters.  Genera which are polymorphic
+in one country seem to be, with some few exceptions, polymorphic in other
+countries, and likewise, judging from Brachiopod shells, at former periods
+of time.  These facts seem to be very perplexing, for they seem to show
+that this kind of variability is independent of the conditions of life.  I
+am inclined to suspect that we see in these polymorphic genera variations
+in points of structure which are of no service or disservice to the
+species, and which consequently have not been seized on and rendered
+definite by natural selection, as hereafter will be explained.
+</para>
+
+<para>
+Those forms which possess in some considerable degree the character of
+species, but which are so closely similar to some other forms, or are so
+closely linked to them by intermediate gradations, that naturalists do not
+like to rank them as distinct species, are in several respects the most
+important for us.  We have every reason to believe that many of these
+doubtful and closely-allied forms have permanently retained their
+characters in their own country for a long time; for as long, as far as we
+know, as have good and true species.  Practically, when a naturalist can
+unite two forms together by others having intermediate characters, he
+treats the one as a variety of the other, ranking the most common, but
+sometimes the one first described, as the species, and the other as the
+variety.  But cases of great difficulty, which I will not here enumerate,
+sometimes occur in deciding whether or not to rank one form as a variety of
+another, even when they are closely connected by intermediate links; nor
+will the commonly-assumed hybrid nature of the intermediate links always
+remove the difficulty.  In very many cases, however, one form is ranked as
+a variety of another, not because the intermediate links have actually been
+found, but because analogy leads the observer to suppose either that they
+do now somewhere exist, or may formerly have existed; and here a wide door
+for the entry of doubt and conjecture is opened.
+</para>
+
+<para>
+Hence, in determining whether a form should be ranked as a species or a
+variety, the opinion of naturalists having sound judgment and wide
+experience seems the only guide to follow.  We must, however, in many
+cases, decide by a majority of naturalists, for few well-marked and
+well-known varieties can be named which have not been ranked as species by
+at least some competent judges.
+</para>
+
+<para>
+That varieties of this doubtful nature are far from uncommon cannot be
+disputed.  Compare the several floras of Great Britain, of France or of the
+United States, drawn up by different botanists, and see what a surprising
+number of forms have been ranked by one botanist as good species, and by
+another as mere varieties.  Mr. H. C. Watson, to whom I lie under deep
+obligation for assistance of all kinds, has marked for me 182 British
+plants, which are generally considered as varieties, but which have all
+been ranked by botanists as species; and in making this list he has omitted
+many trifling varieties, but which nevertheless have been ranked by some
+botanists as species, and he has entirely omitted several highly
+polymorphic genera.  Under genera, including the most polymorphic forms,
+Mr. Babington gives 251 species, whereas Mr. Bentham gives only 112,--a
+difference of 139 doubtful forms!  Amongst animals which unite for each
+birth, and which are highly locomotive, doubtful forms, ranked by one
+zoologist as a species and by another as a variety, can rarely be found
+within the same country, but are common in separated areas.  How many of
+those birds and insects in North America and Europe, which differ very
+slightly from each other, have been ranked by one eminent naturalist as
+undoubted species, and by another as varieties, or, as they are often
+called, as geographical races!  Many years ago, when comparing, and seeing
+others compare, the birds from the separate islands of the Galapagos
+Archipelago, both one with another, and with those from the American
+mainland, I was much struck how entirely vague and arbitrary is the
+distinction between species and varieties.  On the islets of the little
+Madeira group there are many insects which are characterized as varieties
+in Mr. Wollaston's admirable work, but which it cannot be doubted would be
+ranked as distinct species by many entomologists.  Even Ireland has a few
+animals, now generally regarded as varieties, but which have been ranked as
+species by some zoologists.  Several most experienced ornithologists
+consider our British red grouse as only a strongly-marked race of a
+Norwegian species, whereas the greater number rank it as an undoubted
+species peculiar to Great Britain.  A wide distance between the homes of
+two doubtful forms leads many naturalists to rank both as distinct species;
+but what distance, it has been well asked, will suffice? if that between
+America and Europe is ample, will that between the Continent and the
+Azores, or Madeira, or the Canaries, or Ireland, be sufficient?  It must be
+admitted that many forms, considered by highly-competent judges as
+varieties, have so perfectly the character of species that they are ranked
+by other highly-competent judges as good and true species.  But to discuss
+whether they are rightly called species or varieties, before any definition
+of these terms has been generally accepted, is vainly to beat the air.
+</para>
+
+<para>
+Many of the cases of strongly-marked varieties or doubtful species well
+deserve consideration; for several interesting lines of argument, from
+geographical distribution, analogical variation, hybridism, &amp;c., have been
+brought to bear on the attempt to determine their rank.  I will here give
+only a single instance,--the well-known one of the primrose and cowslip, or
+Primula veris and elatior.  These plants differ considerably in appearance;
+they have a different flavour and emit a different odour; they flower at
+slightly different periods; they grow in somewhat different stations; they
+ascend mountains to different heights; they have different geographical
+ranges; and lastly, according to very numerous experiments made during
+several years by that most careful observer Gartner, they can be crossed
+only with much difficulty.  We could hardly wish for better evidence of the
+two forms being specifically distinct.  On the other hand, they are united
+by many intermediate links, and it is very doubtful whether these links are
+hybrids; and there is, as it seems to me, an overwhelming amount of
+experimental evidence, showing that they descend from common parents, and
+consequently must be ranked as varieties.
+</para>
+
+<para>
+Close investigation, in most cases, will bring naturalists to an agreement
+how to rank doubtful forms.  Yet it must be confessed, that it is in the
+best-known countries that we find the greatest number of forms of doubtful
+value.  I have been struck with the fact, that if any animal or plant in a
+state of nature be highly useful to man, or from any cause closely attract
+his attention, varieties of it will almost universally be found recorded. 
+These varieties, moreover, will be often ranked by some authors as species. 
+Look at the common oak, how closely it has been studied; yet a German
+author makes more than a dozen species out of forms, which are very
+generally considered as varieties; and in this country the highest
+botanical authorities and practical men can be quoted to show that the
+sessile and pedunculated oaks are either good and distinct species or mere
+varieties.
+</para>
+
+<para>
+When a young naturalist commences the study of a group of organisms quite
+unknown to him, he is at first much perplexed to determine what differences
+to consider as specific, and what as varieties; for he knows nothing of the
+amount and kind of variation to which the group is subject; and this shows,
+at least, how very generally there is some variation.  But if he confine
+his attention to one class within one country, he will soon make up his
+mind how to rank most of the doubtful forms.  His general tendency will be
+to make many species, for he will become impressed, just like the pigeon or
+poultry-fancier before alluded to, with the amount of difference in the
+forms which he is continually studying; and he has little general knowledge
+of analogical variation in other groups and in other countries, by which to
+correct his first impressions.  As he extends the range of his
+observations, he will meet with more cases of difficulty; for he will
+encounter a greater number of closely-allied forms.  But if his
+observations be widely extended, he will in the end generally be enabled to
+make up his own mind which to call varieties and which species; but he will
+succeed in this at the expense of admitting much variation,--and the truth
+of this admission will often be disputed by other naturalists.  When,
+moreover, he comes to study allied forms brought from countries not now
+continuous, in which case he can hardly hope to find the intermediate links
+between his doubtful forms, he will have to trust almost entirely to
+analogy, and his difficulties will rise to a climax.
+</para>
+
+<para>
+Certainly no clear line of demarcation has as yet been drawn between
+species and sub-species--that is, the forms which in the opinion of some
+naturalists come very near to, but do not quite arrive at the rank of
+species; or, again, between sub-species and well-marked varieties, or
+between lesser varieties and individual differences.  These differences
+blend into each other in an insensible series; and a series impresses the
+mind with the idea of an actual passage.
+</para>
+
+<para>
+Hence I look at individual differences, though of small interest to the
+systematist, as of high importance for us, as being the first step towards
+such slight varieties as are barely thought worth recording in works on
+natural history.  And I look at varieties which are in any degree more
+distinct and permanent, as steps leading to more strongly marked and more
+permanent varieties; and at these latter, as leading to sub-species, and to
+species.  The passage from one stage of difference to another and higher
+stage may be, in some cases, due merely to the long-continued action of
+different physical conditions in two different regions; but I have not much
+faith in this view; and I attribute the passage of a variety, from a state
+in which it differs very slightly from its parent to one in which it
+differs more, to the action of natural selection in accumulating (as will
+hereafter be more fully explained) differences of structure in certain
+definite directions.  Hence I believe a well-marked variety may be justly
+called an incipient species; but whether this belief be justifiable must be
+judged of by the general weight of the several facts and views given
+throughout this work.
+</para>
+
+<para>
+It need not be supposed that all varieties or incipient species necessarily
+attain the rank of species.  They may whilst in this incipient state become
+extinct, or they may endure as varieties for very long periods, as has been
+shown to be the case by Mr. Wollaston with the varieties of certain fossil
+land-shells in Madeira.  If a variety were to flourish so as to exceed in
+numbers the parent species, it would then rank as the species, and the
+species as the variety; or it might come to supplant and exterminate the
+parent species; or both might co-exist, and both rank as independent
+species.  But we shall hereafter have to return to this subject.
+</para>
+
+<para>
+From these remarks it will be seen that I look at the term species, as one
+arbitrarily given for the sake of convenience to a set of individuals
+closely resembling each other, and that it does not essentially differ from
+the term variety, which is given to less distinct and more fluctuating
+forms.  The term variety, again, in comparison with mere individual
+differences, is also applied arbitrarily, and for mere convenience sake.
+</para>
+
+<para>
+Guided by theoretical considerations, I thought that some interesting
+results might be obtained in regard to the nature and relations of the
+species which vary most, by tabulating all the varieties in several
+well-worked floras.  At first this seemed a simple task; but Mr. H. C.
+Watson, to whom I am much indebted for valuable advice and assistance on
+this subject, soon convinced me that there were many difficulties, as did
+subsequently Dr. Hooker, even in stronger terms.  I shall reserve for my
+future work the discussion of these difficulties, and the tables themselves
+of the proportional numbers of the varying species.  Dr. Hooker permits me
+to add, that after having carefully read my manuscript, and examined the
+tables, he thinks that the following statements are fairly well
+established.  The whole subject, however, treated as it necessarily here is
+with much brevity, is rather perplexing, and allusions cannot be avoided to
+the 'struggle for existence,' 'divergence of character,' and other
+questions, hereafter to be discussed.
+</para>
+
+<para>
+Alph. De Candolle and others have shown that plants which have very wide
+ranges generally present varieties; and this might have been expected, as
+they become exposed to diverse physical conditions, and as they come into
+competition (which, as we shall hereafter see, is a far more important
+circumstance) with different sets of organic beings.  But my tables further
+show that, in any limited country, the species which are most common, that
+is abound most in individuals, and the species which are most widely
+diffused within their own country (and this is a different consideration
+from wide range, and to a certain extent from commonness), often give rise
+to varieties sufficiently well-marked to have been recorded in botanical
+works.  Hence it is the most flourishing, or, as they may be called, the
+dominant species,--those which range widely over the world, are the most
+diffused in their own country, and are the most numerous in
+individuals,--which oftenest produce well-marked varieties, or, as I
+consider them, incipient species.  And this, perhaps, might have been
+anticipated; for, as varieties, in order to become in any degree permanent,
+necessarily have to struggle with the other inhabitants of the country, the
+species which are already dominant will be the most likely to yield
+offspring which, though in some slight degree modified, will still inherit
+those advantages that enabled their parents to become dominant over their
+compatriots.
+</para>
+
+<para>
+If the plants inhabiting a country and described in any Flora be divided
+into two equal masses, all those in the larger genera being placed on one
+side, and all those in the smaller genera on the other side, a somewhat
+larger number of the very common and much diffused or dominant species will
+be found on the side of the larger genera.  This, again, might have been
+anticipated; for the mere fact of many species of the same genus inhabiting
+any country, shows that there is something in the organic or inorganic
+conditions of that country favourable to the genus; and, consequently, we
+might have expected to have found in the larger genera, or those including
+many species, a large proportional number of dominant species.  But so many
+causes tend to obscure this result, that I am surprised that my tables show
+even a small majority on the side of the larger genera.  I will here allude
+to only two causes of obscurity.  Fresh-water and salt-loving plants have
+generally very wide ranges and are much diffused, but this seems to be
+connected with the nature of the stations inhabited by them, and has little
+or no relation to the size of the genera to which the species belong. 
+Again, plants low in the scale of organisation are generally much more
+widely diffused than plants higher in the scale; and here again there is no
+close relation to the size of the genera.  The cause of lowly-organised
+plants ranging widely will be discussed in our chapter on geographical
+distribution.
+</para>
+
+<para>
+From looking at species as only strongly-marked and well-defined varieties,
+I was led to anticipate that the species of the larger genera in each
+country would oftener present varieties, than the species of the smaller
+genera; for wherever many closely related species (i.e. species of the same
+genus) have been formed, many varieties or incipient species ought, as a
+general rule, to be now forming.  Where many large trees grow, we expect to
+find saplings.  Where many species of a genus have been formed through
+variation, circumstances have been favourable for variation; and hence we
+might expect that the circumstances would generally be still favourable to
+variation.  On the other hand, if we look at each species as a special act
+of creation, there is no apparent reason why more varieties should occur in
+a group having many species, than in one having few.
+</para>
+
+<para>
+To test the truth of this anticipation I have arranged the plants of twelve
+countries, and the coleopterous insects of two districts, into two nearly
+equal masses, the species of the larger genera on one side, and those of
+the smaller genera on the other side, and it has invariably proved to be
+the case that a larger proportion of the species on the side of the larger
+genera present varieties, than on the side of the smaller genera. 
+Moreover, the species of the large genera which present any varieties,
+invariably present a larger average number of varieties than do the species
+of the small genera.  Both these results follow when another division is
+made, and when all the smallest genera, with from only one to four species,
+are absolutely excluded from the tables.  These facts are of plain
+signification on the view that species are only strongly marked and
+permanent varieties; for whenever many species of the same genus have been
+formed, or where, if we may use the expression, the manufactory of species
+has been active, we ought generally to find the manufactory still in
+action, more especially as we have every reason to believe the process of
+manufacturing new species to be a slow one.  And this certainly is the
+case, if varieties be looked at as incipient species; for my tables clearly
+show as a general rule that, wherever many species of a genus have been
+formed, the species of that genus present a number of varieties, that is of
+incipient species, beyond the average.  It is not that all large genera are
+now varying much, and are thus increasing in the number of their species,
+or that no small genera are now varying and increasing; for if this had
+been so, it would have been fatal to my theory; inasmuch as geology plainly
+tells us that small genera have in the lapse of time often increased
+greatly in size; and that large genera have often come to their maxima,
+declined, and disappeared.  All that we want to show is, that where many
+species of a genus have been formed, on an average many are still forming;
+and this holds good.
+</para>
+
+<para>
+There are other relations between the species of large genera and their
+recorded varieties which deserve notice.  We have seen that there is no
+infallible criterion by which to distinguish species and well-marked
+varieties; and in those cases in which intermediate links have not been
+found between doubtful forms, naturalists are compelled to come to a
+determination by the amount of difference between them, judging by analogy
+whether or not the amount suffices to raise one or both to the rank of
+species.  Hence the amount of difference is one very important criterion in
+settling whether two forms should be ranked as species or varieties.  Now
+Fries has remarked in regard to plants, and Westwood in regard to insects,
+that in large genera the amount of difference between the species is often
+exceedingly small.  I have endeavoured to test this numerically by
+averages, and, as far as my imperfect results go, they always confirm the
+view.  I have also consulted some sagacious and most experienced observers,
+and, after deliberation, they concur in this view.  In this respect,
+therefore, the species of the larger genera resemble varieties, more than
+do the species of the smaller genera.  Or the case may be put in another
+way, and it may be said, that in the larger genera, in which a number of
+varieties or incipient species greater than the average are now
+manufacturing, many of the species already manufactured still to a certain
+extent resemble varieties, for they differ from each other by a less than
+usual amount of difference.
+</para>
+
+<para>
+Moreover, the species of the large genera are related to each other, in the
+same manner as the varieties of any one species are related to each other. 
+No naturalist pretends that all the species of a genus are equally distinct
+from each other; they may generally be divided into sub-genera, or
+sections, or lesser groups.  As Fries has well remarked, little groups of
+species are generally clustered like satellites around certain other
+species.  And what are varieties but groups of forms, unequally related to
+each other, and clustered round certain forms--that is, round their
+parent-species?  Undoubtedly there is one most important point of
+difference between varieties and species; namely, that the amount of
+difference between varieties, when compared with each other or with their
+parent-species, is much less than that between the species of the same
+genus.  But when we come to discuss the principle, as I call it, of
+Divergence of Character, we shall see how this may be explained, and how
+the lesser differences between varieties will tend to increase into the
+greater differences between species.
+</para>
+
+<para>
+There is one other point which seems to me worth notice.  Varieties
+generally have much restricted ranges:  this statement is indeed scarcely
+more than a truism, for if a variety were found to have a wider range than
+that of its supposed parent-species, their denominations ought to be
+reversed.  But there is also reason to believe, that those species which
+are very closely allied to other species, and in so far resemble varieties,
+often have much restricted ranges.  For instance, Mr. H. C. Watson has
+marked for me in the well-sifted London Catalogue of plants (4th edition)
+63 plants which are therein ranked as species, but which he considers as so
+closely allied to other species as to be of doubtful value:  these 63
+reputed species range on an average over 6.9 of the provinces into which
+Mr. Watson has divided Great Britain.  Now, in this same catalogue, 53
+acknowledged varieties are recorded, and these range over 7.7 provinces;
+whereas, the species to which these varieties belong range over 14.3
+provinces.  So that the acknowledged varieties have very nearly the same
+restricted average range, as have those very closely allied forms, marked
+for me by Mr. Watson as doubtful species, but which are almost universally
+ranked by British botanists as good and true species.
+</para>
+
+<para>
+Finally, then, varieties have the same general characters as species, for
+they cannot be distinguished from species,--except, firstly, by the
+discovery of intermediate linking forms, and the occurrence of such links
+cannot affect the actual characters of the forms which they connect; and
+except, secondly, by a certain amount of difference, for two forms, if
+differing very little, are generally ranked as varieties, notwithstanding
+that intermediate linking forms have not been discovered; but the amount of
+difference considered necessary to give to two forms the rank of species is
+quite indefinite.  In genera having more than the average number of species
+in any country, the species of these genera have more than the average
+number of varieties.  In large genera the species are apt to be closely,
+but unequally, allied together, forming little clusters round certain
+species.  Species very closely allied to other species apparently have
+restricted ranges.  In all these several respects the species of large
+genera present a strong analogy with varieties.  And we can clearly
+understand these analogies, if species have once existed as varieties, and
+have thus originated:  whereas, these analogies are utterly inexplicable if
+each species has been independently created.
+</para>
+
+<para>
+We have, also, seen that it is the most flourishing and dominant species of
+the larger genera which on an average vary most; and varieties, as we shall
+hereafter see, tend to become converted into new and distinct species.  The
+larger genera thus tend to become larger; and throughout nature the forms
+of life which are now dominant tend to become still more dominant by
+leaving many modified and dominant descendants.  But by steps hereafter to
+be explained, the larger genera also tend to break up into smaller genera. 
+And thus, the forms of life throughout the universe become divided into
+groups subordinate to groups.
+</para>
+
+</chapter>
+
+<chapter>
+<chapheader>
+
+<chapnum>Chapter III</chapnum>
+
+<title>Struggle for Existence</title>
+
+<chapsummary>
+Bears on natural selection -- The term used in a wide sense -- Geometrical
+powers of increase -- Rapid increase of naturalised animals and plants --
+Nature of the checks to increase -- Competition universal -- Effects of
+climate -- Protection from the number of individuals -- Complex relations
+of all animals and plants throughout nature -- Struggle for life most
+severe between individuals and varieties of the same species; often severe
+between species of the same genus -- The relation of organism to organism
+the most important of all relations.
+</chapsummary>
+</chapheader>
+
+<para> 
+Before entering on the subject of this chapter, I must make a few
+preliminary remarks, to show how the struggle for existence bears on
+Natural Selection.  It has been seen in the last chapter that amongst
+organic beings in a state of nature there is some individual variability;
+indeed I am not aware that this has ever been disputed.  It is immaterial
+for us whether a multitude of doubtful forms be called species or
+sub-species or varieties; what rank, for instance, the two or three hundred
+doubtful forms of British plants are entitled to hold, if the existence of
+any well-marked varieties be admitted.  But the mere existence of
+individual variability and of some few well-marked varieties, though
+necessary as the foundation for the work, helps us but little in
+understanding how species arise in nature.  How have all those exquisite
+adaptations of one part of the organisation to another part, and to the
+conditions of life, and of one distinct organic being to another being,
+been perfected?  We see these beautiful co-adaptations most plainly in the
+woodpecker and missletoe; and only a little less plainly in the humblest
+parasite which clings to the hairs of a quadruped or feathers of a bird; in
+the structure of the beetle which dives through the water; in the plumed
+seed which is wafted by the gentlest breeze; in short, we see beautiful
+adaptations everywhere and in every part of the organic world.
+</para>
+
+<para>
+Again, it may be asked, how is it that varieties, which I have called
+incipient species, become ultimately converted into good and distinct
+species, which in most cases obviously differ from each other far more than
+do the varieties of the same species?  How do those groups of species,
+which constitute what are called distinct genera, and which differ from
+each other more than do the species of the same genus, arise?  All these
+results, as we shall more fully see in the next chapter, follow inevitably
+from the struggle for life.  Owing to this struggle for life, any
+variation, however slight and from whatever cause proceeding, if it be in
+any degree profitable to an individual of any species, in its infinitely
+complex relations to other organic beings and to external nature, will tend
+to the preservation of that individual, and will generally be inherited by
+its offspring.  The offspring, also, will thus have a better chance of
+surviving, for, of the many individuals of any species which are
+periodically born, but a small number can survive.  I have called this
+principle, by which each slight variation, if useful, is preserved, by the
+term of Natural Selection, in order to mark its relation to man's power of
+selection.  We have seen that man by selection can certainly produce great
+results, and can adapt organic beings to his own uses, through the
+accumulation of slight but useful variations, given to him by the hand of
+Nature.  But Natural Selection, as we shall hereafter see, is a power
+incessantly ready for action, and is as immeasurably superior to man's
+feeble efforts, as the works of Nature are to those of Art.
+</para>
+
+<para>
+We will now discuss in a little more detail the struggle for existence.  In
+my future work this subject shall be treated, as it well deserves, at much
+greater length.  The elder De Candolle and Lyell have largely and
+philosophically shown that all organic beings are exposed to severe
+competition.  In regard to plants, no one has treated this subject with
+more spirit and ability than W. Herbert, Dean of Manchester, evidently the
+result of his great horticultural knowledge.  Nothing is easier than to
+admit in words the truth of the universal struggle for life, or more
+difficult--at least I have found it so--than constantly to bear this
+conclusion in mind.  Yet unless it be thoroughly engrained in the mind, I
+am convinced that the whole economy of nature, with every fact on
+distribution, rarity, abundance, extinction, and variation, will be dimly
+seen or quite misunderstood.  We behold the face of nature bright with
+gladness, we often see superabundance of food; we do not see, or we forget,
+that the birds which are idly singing round us mostly live on insects or
+seeds, and are thus constantly destroying life; or we forget how largely
+these songsters, or their eggs, or their nestlings, are destroyed by birds
+and beasts of prey; we do not always bear in mind, that though food may be
+now superabundant, it is not so at all seasons of each recurring year.
+</para>
+
+<para>
+I should premise that I use the term Struggle for Existence in a large and
+metaphorical sense, including dependence of one being on another, and
+including (which is more important) not only the life of the individual,
+but success in leaving progeny.  Two canine animals in a time of dearth,
+may be truly said to struggle with each other which shall get food and
+live.  But a plant on the edge of a desert is said to struggle for life
+against the drought, though more properly it should be said to be dependent
+on the moisture.  A plant which annually produces a thousand seeds, of
+which on an average only one comes to maturity, may be more truly said to
+struggle with the plants of the same and other kinds which already clothe
+the ground.  The missletoe is dependent on the apple and a few other trees,
+but can only in a far-fetched sense be said to struggle with these trees,
+for if too many of these parasites grow on the same tree, it will languish
+and die.  But several seedling missletoes, growing close together on the
+same branch, may more truly be said to struggle with each other.  As the
+missletoe is disseminated by birds, its existence depends on birds; and it
+may metaphorically be said to struggle with other fruit-bearing plants, in
+order to tempt birds to devour and thus disseminate its seeds rather than
+those of other plants.  In these several senses, which pass into each
+other, I use for convenience sake the general term of struggle for
+existence.
+</para>
+
+<para>
+A struggle for existence inevitably follows from the high rate at which all
+organic beings tend to increase.  Every being, which during its natural
+lifetime produces several eggs or seeds, must suffer destruction during
+some period of its life, and during some season or occasional year,
+otherwise, on the principle of geometrical increase, its numbers would
+quickly become so inordinately great that no country could support the
+product.  Hence, as more individuals are produced than can possibly
+survive, there must in every case be a struggle for existence, either one
+individual with another of the same species, or with the individuals of
+distinct species, or with the physical conditions of life.  It is the
+doctrine of Malthus applied with manifold force to the whole animal and
+vegetable kingdoms; for in this case there can be no artificial increase of
+food, and no prudential restraint from marriage.  Although some species may
+be now increasing, more or less rapidly, in numbers, all cannot do so, for
+the world would not hold them.
+</para>
+
+<para>
+There is no exception to the rule that every organic being naturally
+increases at so high a rate, that if not destroyed, the earth would soon be
+covered by the progeny of a single pair.  Even slow-breeding man has
+doubled in twenty-five years, and at this rate, in a few thousand years,
+there would literally not be standing room for his progeny.  Linnaeus has
+calculated that if an annual plant produced only two seeds--and there is no
+plant so unproductive as this--and their seedlings next year produced two,
+and so on, then in twenty years there would be a million plants.  The
+elephant is reckoned to be the slowest breeder of all known animals, and I
+have taken some pains to estimate its probable minimum rate of natural
+increase:  it will be under the mark to assume that it breeds when thirty
+years old, and goes on breeding till ninety years old, bringing forth three
+pair of young in this interval; if this be so, at the end of the fifth
+century there would be alive fifteen million elephants, descended from the
+first pair.
+</para>
+
+<para>
+But we have better evidence on this subject than mere theoretical
+calculations, namely, the numerous recorded cases of the astonishingly
+rapid increase of various animals in a state of nature, when circumstances
+have been favourable to them during two or three following seasons.  Still
+more striking is the evidence from our domestic animals of many kinds which
+have run wild in several parts of the world:  if the statements of the rate
+of increase of slow-breeding cattle and horses in South America, and
+latterly in Australia, had not been well authenticated, they would have
+been quite incredible.  So it is with plants:  cases could be given of
+introduced plants which have become common throughout whole islands in a
+period of less than ten years.  Several of the plants now most numerous
+over the wide plains of La Plata, clothing square leagues of surface almost
+to the exclusion of all other plants, have been introduced from Europe; and
+there are plants which now range in India, as I hear from Dr. Falconer,
+from Cape Comorin to the Himalaya, which have been imported from America
+since its discovery.  In such cases, and endless instances could be given,
+no one supposes that the fertility of these animals or plants has been
+suddenly and temporarily increased in any sensible degree.  The obvious
+explanation is that the conditions of life have been very favourable, and
+that there has consequently been less destruction of the old and young, and
+that nearly all the young have been enabled to breed.  In such cases the
+geometrical ratio of increase, the result of which never fails to be
+surprising, simply explains the extraordinarily rapid increase and wide
+diffusion of naturalised productions in their new homes.
+</para>
+
+<para>
+In a state of nature almost every plant produces seed, and amongst animals
+there are very few which do not annually pair.  Hence we may confidently
+assert, that all plants and animals are tending to increase at a
+geometrical ratio, that all would most rapidly stock every station in which
+they could any how exist, and that the geometrical tendency to increase
+must be checked by destruction at some period of life.  Our familiarity
+with the larger domestic animals tends, I think, to mislead us:  we see no
+great destruction falling on them, and we forget that thousands are
+annually slaughtered for food, and that in a state of nature an equal
+number would have somehow to be disposed of.
+</para>
+
+<para>
+The only difference between organisms which annually produce eggs or seeds
+by the thousand, and those which produce extremely few, is, that the
+slow-breeders would require a few more years to people, under favourable
+conditions, a whole district, let it be ever so large.  The condor lays a
+couple of eggs and the ostrich a score, and yet in the same country the
+condor may be the more numerous of the two:  the Fulmar petrel lays but one
+egg, yet it is believed to be the most numerous bird in the world.  One fly
+deposits hundreds of eggs, and another, like the hippobosca, a single one;
+but this difference does not determine how many individuals of the two
+species can be supported in a district.  A large number of eggs is of some
+importance to those species, which depend on a rapidly fluctuating amount
+of food, for it allows them rapidly to increase in number.  But the real
+importance of a large number of eggs or seeds is to make up for much
+destruction at some period of life; and this period in the great majority
+of cases is an early one.  If an animal can in any way protect its own eggs
+or young, a small number may be produced, and yet the average stock be
+fully kept up; but if many eggs or young are destroyed, many must be
+produced, or the species will become extinct.  It would suffice to keep up
+the full number of a tree, which lived on an average for a thousand years,
+if a single seed were produced once in a thousand years, supposing that
+this seed were never destroyed, and could be ensured to germinate in a
+fitting place.  So that in all cases, the average number of any animal or
+plant depends only indirectly on the number of its eggs or seeds.
+</para>
+
+<para>
+In looking at Nature, it is most necessary to keep the foregoing
+considerations always in mind--never to forget that every single organic
+being around us may be said to be striving to the utmost to increase in
+numbers; that each lives by a struggle at some period of its life; that
+heavy destruction inevitably falls either on the young or old, during each
+generation or at recurrent intervals.  Lighten any check, mitigate the 
+destruction ever so little, and the number of the species will almost
+instantaneously increase to any amount.  The face of Nature may be compared
+to a yielding surface, with ten thousand sharp wedges packed close together
+and driven inwards by incessant blows, sometimes one wedge being struck,
+and then another with greater force.
+</para>
+
+<para>
+What checks the natural tendency of each species to increase in number is
+most obscure.  Look at the most vigorous species; by as much as it swarms
+in numbers, by so much will its tendency to increase be still further
+increased.  We know not exactly what the checks are in even one single
+instance.  Nor will this surprise any one who reflects how ignorant we are
+on this head, even in regard to mankind, so incomparably better known than
+any other animal.  This subject has been ably treated by several authors,
+and I shall, in my future work, discuss some of the checks at considerable
+length, more especially in regard to the feral animals of South America. 
+Here I will make only a few remarks, just to recall to the reader's mind
+some of the chief points.  Eggs or very young animals seem generally to
+suffer most, but this is not invariably the case.  With plants there is a
+vast destruction of seeds, but, from some observations which I have made, I
+believe that it is the seedlings which suffer most from germinating in
+ground already thickly stocked with other plants.  Seedlings, also, are
+destroyed in vast numbers by various enemies; for instance, on a piece of
+ground three feet long and two wide, dug and cleared, and where there could
+be no choking from other plants, I marked all the seedlings of our native
+weeds as they came up, and out of the 357 no less than 295 were destroyed,
+chiefly by slugs and insects.  If turf which has long been mown, and the
+case would be the same with turf closely browsed by quadrupeds, be let to
+grow, the more vigorous plants gradually kill the less vigorous, though
+fully grown, plants:  thus out of twenty species growing on a little plot
+of turf (three feet by four) nine species perished from the other species
+being allowed to grow up freely.
+</para>
+
+<para>
+The amount of food for each species of course gives the extreme limit to
+which each can increase; but very frequently it is not the obtaining food,
+but the serving as prey to other animals, which determines the average
+numbers of a species.  Thus, there seems to be little doubt that the stock
+of partridges, grouse, and hares on any large estate depends chiefly on the
+destruction of vermin.  If not one head of game were shot during the next
+twenty years in England, and, at the same time, if no vermin were
+destroyed, there would, in all probability, be less game than at present,
+although hundreds of thousands of game animals are now annually killed.  On
+the other hand, in some cases, as with the elephant and rhinoceros, none
+are destroyed by beasts of prey:  even the tiger in India most rarely dares
+to attack a young elephant protected by its dam.
+</para>
+
+<para>
+Climate plays an important part in determining the average numbers of a
+species, and periodical seasons of extreme cold or drought, I believe to be
+the most effective of all checks.  I estimated that the winter of 1854-55
+destroyed four-fifths of the birds in my own grounds; and this is a
+tremendous destruction, when we remember that ten per cent. is an
+extraordinarily severe mortality from epidemics with man.  The action of
+climate seems at first sight to be quite independent of the struggle for
+existence; but in so far as climate chiefly acts in reducing food, it
+brings on the most severe struggle between the individuals, whether of the
+same or of distinct species, which subsist on the same kind of food.  Even
+when climate, for instance extreme cold, acts directly, it will be the
+least vigorous, or those which have got least food through the advancing
+winter, which will suffer most.  When we travel from south to north, or
+from a damp region to a dry, we invariably see some species gradually
+getting rarer and rarer, and finally disappearing; and the change of
+climate being conspicuous, we are tempted to attribute the whole effect to
+its direct action.  But this is a very false view:  we forget that each
+species, even where it most abounds, is constantly suffering enormous
+destruction at some period of its life, from enemies or from competitors
+for the same place and food; and if these enemies or competitors be in the
+least degree favoured by any slight change of climate, they will increase
+in numbers, and, as each area is already fully stocked with inhabitants,
+the other species will decrease.  When we travel southward and see a
+species decreasing in numbers, we may feel sure that the cause lies quite
+as much in other species being favoured, as in this one being hurt.  So it
+is when we travel northward, but in a somewhat lesser degree, for the
+number of species of all kinds, and therefore of competitors, decreases
+northwards; hence in going northward, or in ascending a mountain, we far
+oftener meet with stunted forms, due to the directly injurious action of
+climate, than we do in proceeding southwards or in descending a mountain. 
+When we reach the Arctic regions, or snow-capped summits, or absolute
+deserts, the struggle for life is almost exclusively with the elements.
+</para>
+
+<para>
+That climate acts in main part indirectly by favouring other species, we
+may clearly see in the prodigious number of plants in our gardens which can
+perfectly well endure our climate, but which never become naturalised, for
+they cannot compete with our native plants, nor resist destruction by our
+native animals.
+</para>
+
+<para>
+When a species, owing to highly favourable circumstances, increases
+inordinately in numbers in a small tract, epidemics--at least, this seems
+generally to occur with our game animals--often ensue:  and here we have a
+limiting check independent of the struggle for life.  But even some of
+these so-called epidemics appear to be due to parasitic worms, which have
+from some cause, possibly in part through facility of diffusion amongst the
+crowded animals, been disproportionably favoured:  and here comes in a sort
+of struggle between the parasite and its prey.
+</para>
+
+<para>
+On the other hand, in many cases, a large stock of individuals of the same
+species, relatively to the numbers of its enemies, is absolutely necessary
+for its preservation.  Thus we can easily raise plenty of corn and
+rape-seed, &amp;c., in our fields, because the seeds are in great excess
+compared with the number of birds which feed on them; nor can the birds,
+though having a superabundance of food at this one season, increase in
+number proportionally to the supply of seed, as their numbers are checked
+during winter:  but any one who has tried, knows how troublesome it is to
+get seed from a few wheat or other such plants in a garden; I have in this
+case lost every single seed.  This view of the necessity of a large stock
+of the same species for its preservation, explains, I believe, some
+singular facts in nature, such as that of very rare plants being sometimes
+extremely abundant in the few spots where they do occur; and that of some
+social plants being social, that is, abounding in individuals, even on the
+extreme confines of their range.  For in such cases, we may believe, that a
+plant could exist only where the conditions of its life were so favourable
+that many could exist together, and thus save each other from utter
+destruction.  I should add that the good effects of frequent intercrossing,
+and the ill effects of close interbreeding, probably come into play in some
+of these cases; but on this intricate subject I will not here enlarge.
+</para>
+
+<para>
+Many cases are on record showing how complex and unexpected are the checks
+and relations between organic beings, which have to struggle together in
+the same country.  I will give only a single instance, which, though a
+simple one, has interested me.  In Staffordshire, on the estate of a
+relation where I had ample means of investigation, there was a large and
+extremely barren heath, which had never been touched by the hand of man;
+but several hundred acres of exactly the same nature had been enclosed
+twenty-five years previously and planted with Scotch fir.  The change in
+the native vegetation of the planted part of the heath was most remarkable,
+more than is generally seen in passing from one quite different soil to
+another:  not only the proportional numbers of the heath-plants were wholly
+changed, but twelve species of plants (not counting grasses and carices)
+flourished in the plantations, which could not be found on the heath.  The
+effect on the insects must have been still greater, for six insectivorous
+birds were very common in the plantations, which were not to be seen on the
+heath; and the heath was frequented by two or three distinct insectivorous
+birds.  Here we see how potent has been the effect of the introduction of a
+single tree, nothing whatever else having been done, with the exception
+that the land had been enclosed, so that cattle could not enter.  But how
+important an element enclosure is, I plainly saw near Farnham, in Surrey. 
+Here there are extensive heaths, with a few clumps of old Scotch firs on
+the distant hill-tops:  within the last ten years large spaces have been
+enclosed, and self-sown firs are now springing up in multitudes, so close
+together that all cannot live.
+</para>
+
+<para>
+When I ascertained that these young trees had not been sown or planted, I
+was so much surprised at their numbers that I went to several points of
+view, whence I could examine hundreds of acres of the unenclosed heath, and
+literally I could not see a single Scotch fir, except the old planted
+clumps.  But on looking closely between the stems of the heath, I found a
+multitude of seedlings and little trees, which had been perpetually browsed
+down by the cattle.  In one square yard, at a point some hundreds yards
+distant from one of the old clumps, I counted thirty-two little trees; and
+one of them, judging from the rings of growth, had during twenty-six years
+tried to raise its head above the stems of the heath, and had failed.  No
+wonder that, as soon as the land was enclosed, it became thickly clothed
+with vigorously growing young firs.  Yet the heath was so extremely barren
+and so extensive that no one would ever have imagined that cattle would
+have so closely and effectually searched it for food.
+</para>
+
+<para>
+Here we see that cattle absolutely determine the existence of the Scotch
+fir; but in several parts of the world insects determine the existence of
+cattle.  Perhaps Paraguay offers the most curious instance of this; for
+here neither cattle nor horses nor dogs have ever run wild, though they
+swarm southward and northward in a feral state; and Azara and Rengger have
+shown that this is caused by the greater number in Paraguay of a certain
+fly, which lays its eggs in the navels of these animals when first born. 
+The increase of these flies, numerous as they are, must be habitually
+checked by some means, probably by birds.  Hence, if certain insectivorous
+birds (whose numbers are probably regulated by hawks or beasts of prey)
+were to increase in Paraguay, the flies would decrease--then cattle and
+horses would become feral, and this would certainly greatly alter (as
+indeed I have observed in parts of South America) the vegetation:  this
+again would largely affect the insects; and this, as we just have seen in
+Staffordshire, the insectivorous birds, and so onwards in ever-increasing
+circles of complexity.  We began this series by insectivorous birds, and we
+have ended with them.  Not that in nature the relations can ever be as
+simple as this.  Battle within battle must ever be recurring with varying
+success; and yet in the long-run the forces are so nicely balanced, that
+the face of nature remains uniform for long periods of time, though
+assuredly the merest trifle would often give the victory to one organic
+being over another.  Nevertheless so profound is our ignorance, and so high
+our presumption, that we marvel when we hear of the extinction of an
+organic being; and as we do not see the cause, we invoke cataclysms to
+desolate the world, or invent laws on the duration of the forms of life!
+</para>
+
+<para>
+I am tempted to give one more instance showing how plants and animals, most
+remote in the scale of nature, are bound together by a web of complex
+relations.  I shall hereafter have occasion to show that the exotic Lobelia
+fulgens, in this part of England, is never visited by insects, and
+consequently, from its peculiar structure, never can set a seed.  Many of
+our orchidaceous plants absolutely require the visits of moths to remove
+their pollen-masses and thus to fertilise them.  I have, also, reason to
+believe that humble-bees are indispensable to the fertilisation of the
+heartsease (Viola tricolor), for other bees do not visit this flower.  From
+experiments which I have tried, I have found that the visits of bees, if
+not indispensable, are at least highly beneficial to the fertilisation of
+our clovers; but humble-bees alone visit the common red clover (Trifolium
+pratense), as other bees cannot reach the nectar.  Hence I have very little
+doubt, that if the whole genus of humble-bees became extinct or very rare
+in England, the heartsease and red clover would become very rare, or wholly
+disappear.  The number of humble-bees in any district depends in a great
+degree on the number of field-mice, which destroy their combs and nests;
+and Mr. H. Newman, who has long attended to the habits of humble-bees,
+believes that 'more than two thirds of them are thus destroyed all over
+England.'  Now the number of mice is largely dependent, as every one knows,
+on the number of cats; and Mr. Newman says, 'Near villages and small towns
+I have found the nests of humble-bees more numerous than elsewhere, which I
+attribute to the number of cats that destroy the mice.'  Hence it is quite
+credible that the presence of a feline animal in large numbers in a
+district might determine, through the intervention first of mice and then
+of bees, the frequency of certain flowers in that district!
+</para>
+
+<para>
+In the case of every species, many different checks, acting at different
+periods of life, and during different seasons or years, probably come into
+play; some one check or some few being generally the most potent, but all
+concurring in determining the average number or even the existence of the
+species.  In some cases it can be shown that widely-different checks act on
+the same species in different districts.  When we look at the plants and
+bushes clothing an entangled bank, we are tempted to attribute their
+proportional numbers and kinds to what we call chance.  But how false a
+view is this!  Every one has heard that when an American forest is cut
+down, a very different vegetation springs up; but it has been observed that
+the trees now growing on the ancient Indian mounds, in the Southern United
+States, display the same beautiful diversity and proportion of kinds as in
+the surrounding virgin forests.  What a struggle between the several kinds
+of trees must here have gone on during long centuries, each annually
+scattering its seeds by the thousand; what war between insect and
+insect--between insects, snails, and other animals with birds and beasts of
+prey--all striving to increase, and all feeding on each other or on the
+trees or their seeds and seedlings, or on the other plants which first
+clothed the ground and thus checked the growth of the trees!  Throw up a
+handful of feathers, and all must fall to the ground according to definite
+laws; but how simple is this problem compared to the action and reaction of
+the innumerable plants and animals which have determined, in the course of
+centuries, the proportional numbers and kinds of trees now growing on the
+old Indian ruins!
+</para>
+
+<para>
+The dependency of one organic being on another, as of a parasite on its
+prey, lies generally between beings remote in the scale of nature.  This is
+often the case with those which may strictly be said to struggle with each
+other for existence, as in the case of locusts and grass-feeding
+quadrupeds.  But the struggle almost invariably will be most severe between
+the individuals of the same species, for they frequent the same districts,
+require the same food, and are exposed to the same dangers.  In the case of
+varieties of the same species, the struggle will generally be almost
+equally severe, and we sometimes see the contest soon decided:  for
+instance, if several varieties of wheat be sown together, and the mixed
+seed be resown, some of the varieties which best suit the soil or climate,
+or are naturally the most fertile, will beat the others and so yield more
+seed, and will consequently in a few years quite supplant the other
+varieties.  To keep up a mixed stock of even such extremely close varieties
+as the variously coloured sweet-peas, they must be each year harvested
+separately, and the seed then mixed in due proportion, otherwise the weaker
+kinds will steadily decrease in numbers and disappear.  So again with the
+varieties of sheep:  it has been asserted that certain mountain-varieties
+will starve out other mountain-varieties, so that they cannot be kept
+together.  The same result has followed from keeping together different
+varieties of the medicinal leech.  It may even be doubted whether the
+varieties of any one of our domestic plants or animals have so exactly the
+same strength, habits, and constitution, that the original proportions of a
+mixed stock could be kept up for half a dozen generations, if they were
+allowed to struggle together, like beings in a state of nature, and if the
+seed or young were not annually sorted.
+</para>
+
+<para>
+As species of the same genus have usually, though by no means invariably,
+some similarity in habits and constitution, and always in structure, the
+struggle will generally be more severe between species of the same genus,
+when they come into competition with each other, than between species of
+distinct genera.  We see this in the recent extension over parts of the
+United States of one species of swallow having caused the decrease of
+another species.  The recent increase of the missel-thrush in parts of
+Scotland has caused the decrease of the song-thrush.  How frequently we
+hear of one species of rat taking the place of another species under the
+most different climates!  In Russia the small Asiatic cockroach has
+everywhere driven before it its great congener.  One species of charlock
+will supplant another, and so in other cases.  We can dimly see why the
+competition should be most severe between allied forms, which fill nearly
+the same place in the economy of nature; but probably in no one case could
+we precisely say why one species has been victorious over another in the
+great battle of life.
+</para>
+
+<para>
+A corollary of the highest importance may be deduced from the foregoing
+remarks, namely, that the structure of every organic being is related, in
+the most essential yet often hidden manner, to that of all other organic
+beings, with which it comes into competition for food or residence, or from
+which it has to escape, or on which it preys.  This is obvious in the
+structure of the teeth and talons of the tiger; and in that of the legs and
+claws of the parasite which clings to the hair on the tiger's body.  But in
+the beautifully plumed seed of the dandelion, and in the flattened and
+fringed legs of the water-beetle, the relation seems at first confined to
+the elements of air and water.  Yet the advantage of plumed seeds no doubt
+stands in the closest relation to the land being already thickly clothed by
+other plants; so that the seeds may be widely distributed and fall on
+unoccupied ground.  In the water-beetle, the structure of its legs, so well
+adapted for diving, allows it to compete with other aquatic insects, to
+hunt for its own prey, and to escape serving as prey to other animals.
+</para>
+
+<para>
+The store of nutriment laid up within the seeds of many plants seems at
+first sight to have no sort of relation to other plants.  But from the
+strong growth of young plants produced from such seeds (as peas and beans),
+when sown in the midst of long grass, I suspect that the chief use of the
+nutriment in the seed is to favour the growth of the young seedling, whilst
+struggling with other plants growing vigorously all around.
+</para>
+
+<para>
+Look at a plant in the midst of its range, why does it not double or
+quadruple its numbers?  We know that it can perfectly well withstand a
+little more heat or cold, dampness or dryness, for elsewhere it ranges into
+slightly hotter or colder, damper or drier districts.  In this case we can
+clearly see that if we wished in imagination to give the plant the power of
+increasing in number, we should have to give it some advantage over its
+competitors, or over the animals which preyed on it.  On the confines of
+its geographical range, a change of constitution with respect to climate
+would clearly be an advantage to our plant; but we have reason to believe
+that only a few plants or animals range so far, that they are destroyed by
+the rigour of the climate alone.  Not until we reach the extreme confines
+of life, in the arctic regions or on the borders of an utter desert, will
+competition cease.  The land may be extremely cold or dry, yet there will
+be competition between some few species, or between the individuals of the
+same species, for the warmest or dampest spots.
+</para>
+
+<para>
+Hence, also, we can see that when a plant or animal is placed in a new
+country amongst new competitors, though the climate may be exactly the same
+as in its former home, yet the conditions of its life will generally be
+changed in an essential manner.  If we wished to increase its average
+numbers in its new home, we should have to modify it in a different way to
+what we should have done in its native country; for we should have to give
+it some advantage over a different set of competitors or enemies.
+</para>
+
+<para>
+It is good thus to try in our imagination to give any form some advantage
+over another.  Probably in no single instance should we know what to do, so
+as to succeed.  It will convince us of our ignorance on the mutual
+relations of all organic beings; a conviction as necessary, as it seems to
+be difficult to acquire.  All that we can do, is to keep steadily in mind
+that each organic being is striving to increase at a geometrical ratio;
+that each at some period of its life, during some season of the year,
+during each generation or at intervals, has to struggle for life, and to
+suffer great destruction.  When we reflect on this struggle, we may console
+ourselves with the full belief, that the war of nature is not incessant,
+that no fear is felt, that death is generally prompt, and that the
+vigorous, the healthy, and the happy survive and multiply.
+</para>
+
+</chapter>
+
+<chapter>
+<chapheader>
+
+<chapnum>Chapter IV</chapnum>
+
+<title>Natural Selection</title>
+
+<chapsummary>
+Natural Selection -- its power compared with man's selection -- its power
+on characters of trifling importance -- its power at all ages and on both
+sexes -- Sexual Selection -- On the generality of intercrosses between
+individuals of the same species -- Circumstances favourable and
+unfavourable to Natural Selection, namely, intercrossing, isolation, number
+of individuals -- Slow action -- Extinction caused by Natural Selection --
+Divergence of Character, related to the diversity of inhabitants of any
+small area, and to naturalisation -- Action of Natural Selection, through
+Divergence of Character and Extinction, on the descendants from a common
+parent -- Explains the Grouping of all organic beings.
+</chapsummary>
+</chapheader>
+
+<para>
+How will the struggle for existence, discussed too briefly in the last
+chapter, act in regard to variation?  Can the principle of selection, which
+we have seen is so potent in the hands of man, apply in nature?  I think we
+shall see that it can act most effectually.  Let it be borne in mind in
+what an endless number of strange peculiarities our domestic productions,
+and, in a lesser degree, those under nature, vary; and how strong the
+hereditary tendency is.  Under domestication, it may be truly said that the
+whole organisation becomes in some degree plastic.  Let it be borne in mind
+how infinitely complex and close-fitting are the mutual relations of all
+organic beings to each other and to their physical conditions of life.  Can
+it, then, be thought improbable, seeing that variations useful to man have
+undoubtedly occurred, that other variations useful in some way to each
+being in the great and complex battle of life, should sometimes occur in
+the course of thousands of generations?  If such do occur, can we doubt
+(remembering that many more individuals are born than can possibly survive)
+that individuals having any advantage, however slight, over others, would
+have the best chance of surviving and of procreating their kind?  On the
+other hand, we may feel sure that any variation in the least degree
+injurious would be rigidly destroyed.  This preservation of favourable
+variations and the rejection of injurious variations, I call Natural
+Selection.  Variations neither useful nor injurious would not be affected
+by natural selection, and would be left a fluctuating element, as perhaps
+we see in the species called polymorphic.
+</para>
+
+<para>
+We shall best understand the probable course of natural selection by taking
+the case of a country undergoing some physical change, for instance, of
+climate.  The proportional numbers of its inhabitants would almost
+immediately undergo a change, and some species might become extinct.  We
+may conclude, from what we have seen of the intimate and complex manner in
+which the inhabitants of each country are bound together, that any change
+in the numerical proportions of some of the inhabitants, independently of
+the change of climate itself, would most seriously affect many of the
+others.  If the country were open on its borders, new forms would certainly
+immigrate, and this also would seriously disturb the relations of some of
+the former inhabitants.  Let it be remembered how powerful the influence of
+a single introduced tree or mammal has been shown to be.  But in the case
+of an island, or of a country partly surrounded by barriers, into which new
+and better adapted forms could not freely enter, we should then have places
+in the economy of nature which would assuredly be better filled up, if some
+of the original inhabitants were in some manner modified; for, had the area
+been open to immigration, these same places would have been seized on by
+intruders.  In such case, every slight modification, which in the course of
+ages chanced to arise, and which in any way favoured the individuals of any
+of the species, by better adapting them to their altered conditions, would
+tend to be preserved; and natural selection would thus have free scope for
+the work of improvement.
+</para>
+
+<para>
+We have reason to believe, as stated in the first chapter, that a change in
+the conditions of life, by specially acting on the reproductive system,
+causes or increases variability; and in the foregoing case the conditions
+of life are supposed to have undergone a change, and this would manifestly
+be favourable to natural selection, by giving a better chance of profitable
+variations occurring; and unless profitable variations do occur, natural
+selection can do nothing.  Not that, as I believe, any extreme amount of
+variability is necessary; as man can certainly produce great results by
+adding up in any given direction mere individual differences, so could
+Nature, but far more easily, from having incomparably longer time at her
+disposal.  Nor do I believe that any great physical change, as of climate,
+or any unusual degree of isolation to check immigration, is actually
+necessary to produce new and unoccupied places for natural selection to
+fill up by modifying and improving some of the varying inhabitants.  For as
+all the inhabitants of each country are struggling together with nicely
+balanced forces, extremely slight modifications in the structure or habits
+of one inhabitant would often give it an advantage over others; and still
+further modifications of the same kind would often still further increase
+the advantage.  No country can be named in which all the native inhabitants
+are now so perfectly adapted to each other and to the physical conditions
+under which they live, that none of them could anyhow be improved; for in
+all countries, the natives have been so far conquered by naturalised
+productions, that they have allowed foreigners to take firm possession of
+the land.  And as foreigners have thus everywhere beaten some of the
+natives, we may safely conclude that the natives might have been modified
+with advantage, so as to have better resisted such intruders.
+</para>
+
+<para>
+As man can produce and certainly has produced a great result by his
+methodical and unconscious means of selection, what may not nature effect? 
+Man can act only on external and visible characters:  nature cares nothing
+for appearances, except in so far as they may be useful to any being.  She
+can act on every internal organ, on every shade of constitutional
+difference, on the whole machinery of life.  Man selects only for his own
+good; Nature only for that of the being which she tends.  Every selected
+character is fully exercised by her; and the being is placed under
+well-suited conditions of life.  Man keeps the natives of many climates in
+the same country; he seldom exercises each selected character in some
+peculiar and fitting manner; he feeds a long and a short beaked pigeon on
+the same food; he does not exercise a long-backed or long-legged quadruped
+in any peculiar manner; he exposes sheep with long and short wool to the
+same climate.  He does not allow the most vigorous males to struggle for
+the females.  He does not rigidly destroy all inferior animals, but
+protects during each varying season, as far as lies in his power, all his
+productions.  He often begins his selection by some half-monstrous form; or
+at least by some modification prominent enough to catch his eye, or to be
+plainly useful to him.  Under nature, the slightest difference of structure
+or constitution may well turn the nicely-balanced scale in the struggle for
+life, and so be preserved.  How fleeting are the wishes and efforts of man!
+how short his time! and consequently how poor will his products be,
+compared with those accumulated by nature during whole geological periods. 
+Can we wonder, then, that nature's productions should be far 'truer' in
+character than man's productions; that they should be infinitely better
+adapted to the most complex conditions of life, and should plainly bear the
+stamp of far higher workmanship?
+</para>
+
+<para>
+It may be said that natural selection is daily and hourly scrutinising,
+throughout the world, every variation, even the slightest; rejecting that
+which is bad, preserving and adding up all that is good; silently and
+insensibly working, whenever and wherever opportunity offers, at the
+improvement of each organic being in relation to its organic and inorganic
+conditions of life.  We see nothing of these slow changes in progress,
+until the hand of time has marked the long lapse of ages, and then so
+imperfect is our view into long past geological ages, that we only see that
+the forms of life are now different from what they formerly were.
+</para>
+
+<para>
+Although natural selection can act only through and for the good of each
+being, yet characters and structures, which we are apt to consider as of
+very trifling importance, may thus be acted on.  When we see leaf-eating
+insects green, and bark-feeders mottled-grey; the alpine ptarmigan white in
+winter, the red-grouse the colour of heather, and the black-grouse that of
+peaty earth, we must believe that these tints are of service to these birds
+and insects in preserving them from danger.  Grouse, if not destroyed at
+some period of their lives, would increase in countless numbers; they are
+known to suffer largely from birds of prey; and hawks are guided by
+eyesight to their prey,--so much so, that on parts of the Continent persons
+are warned not to keep white pigeons, as being the most liable to
+destruction.  Hence I can see no reason to doubt that natural selection
+might be most effective in giving the proper colour to each kind of grouse,
+and in keeping that colour, when once acquired, true and constant.  Nor
+ought we to think that the occasional destruction of an animal of any
+particular colour would produce little effect:  we should remember how
+essential it is in a flock of white sheep to destroy every lamb with the
+faintest trace of black.  In plants the down on the fruit and the colour of
+the flesh are considered by botanists as characters of the most trifling
+importance:  yet we hear from an excellent horticulturist, Downing, that in
+the United States smooth-skinned fruits suffer far more from a beetle, a
+curculio, than those with down; that purple plums suffer far more from a
+certain disease than yellow plums; whereas another disease attacks
+yellow-fleshed peaches far more than those with other coloured flesh.  If,
+with all the aids of art, these slight differences make a great difference
+in cultivating the several varieties, assuredly, in a state of nature,
+where the trees would have to struggle with other trees and with a host of
+enemies, such differences would effectually settle which variety, whether a
+smooth or downy, a yellow or purple fleshed fruit, should succeed.
+</para>
+
+<para>
+In looking at many small points of difference between species, which, as
+far as our ignorance permits us to judge, seem to be quite unimportant, we
+must not forget that climate, food, &amp;c., probably produce some slight and
+direct effect.  It is, however, far more necessary to bear in mind that
+there are many unknown laws of correlation of growth, which, when one part
+of the organisation is modified through variation, and the modifications
+are accumulated by natural selection for the good of the being, will cause
+other modifications, often of the most unexpected nature.
+</para>
+
+<para>
+As we see that those variations which under domestication appear at any
+particular period of life, tend to reappear in the offspring at the same
+period;--for instance, in the seeds of the many varieties of our culinary
+and agricultural plants; in the caterpillar and cocoon stages of the
+varieties of the silkworm; in the eggs of poultry, and in the colour of the
+down of their chickens; in the horns of our sheep and cattle when nearly
+adult;--so in a state of nature, natural selection will be enabled to act
+on and modify organic beings at any age, by the accumulation of profitable
+variations at that age, and by their inheritance at a corresponding age. 
+If it profit a plant to have its seeds more and more widely disseminated by
+the wind, I can see no greater difficulty in this being effected through
+natural selection, than in the cotton-planter increasing and improving by
+selection the down in the pods on his cotton-trees.  Natural selection may
+modify and adapt the larva of an insect to a score of contingencies, wholly
+different from those which concern the mature insect.  These modifications
+will no doubt affect, through the laws of correlation, the structure of the
+adult; and probably in the case of those insects which live only for a few
+hours, and which never feed, a large part of their structure is merely the
+correlated result of successive changes in the structure of their larvae. 
+So, conversely, modifications in the adult will probably often affect the
+structure of the larva; but in all cases natural selection will ensure that
+modifications consequent on other modifications at a different period of
+life, shall not be in the least degree injurious:  for if they became so,
+they would cause the extinction of the species.
+</para>
+
+<para>
+Natural selection will modify the structure of the young in relation to the
+parent, and of the parent in relation to the young.  In social animals it
+will adapt the structure of each individual for the benefit of the
+community; if each in consequence profits by the selected change.  What
+natural selection cannot do, is to modify the structure of one species,
+without giving it any advantage, for the good of another species; and
+though statements to this effect may be found in works of natural history,
+I cannot find one case which will bear investigation.  A structure used
+only once in an animal's whole life, if of high importance to it, might be
+modified to any extent by natural selection; for instance, the great jaws
+possessed by certain insects, and used exclusively for opening the
+cocoon--or the hard tip to the beak of nestling birds, used for breaking
+the egg.  It has been asserted, that of the best short-beaked
+tumbler-pigeons more perish in the egg than are able to get out of it; so
+that fanciers assist in the act of hatching.  Now, if nature had to make
+the beak of a full-grown pigeon very short for the bird's own advantage,
+the process of modification would be very slow, and there would be
+simultaneously the most rigorous selection of the young birds within the
+egg, which had the most powerful and hardest beaks, for all with weak beaks
+would inevitably perish:  or, more delicate and more easily broken shells
+might be selected, the thickness of the shell being known to vary like
+every other structure.
+</para>
+
+<para>
+Sexual Selection. -- Inasmuch as peculiarities often appear under
+domestication in one sex and become hereditarily attached to that sex, the
+same fact probably occurs under nature, and if so, natural selection will
+be able to modify one sex in its functional relations to the other sex, or
+in relation to wholly different habits of life in the two sexes, as is
+sometimes the case with insects.  And this leads me to say a few words on
+what I call Sexual Selection.  This depends, not on a struggle for
+existence, but on a struggle between the males for possession of the
+females; the result is not death to the unsuccessful competitor, but few or
+no offspring.  Sexual selection is, therefore, less rigorous than natural
+selection.  Generally, the most vigorous males, those which are best fitted
+for their places in nature, will leave most progeny.  But in many cases,
+victory will depend not on general vigour, but on having special weapons,
+confined to the male sex.  A hornless stag or spurless cock would have a
+poor chance of leaving offspring.  Sexual selection by always allowing the
+victor to breed might surely give indomitable courage, length to the spur,
+and strength to the wing to strike in the spurred leg, as well as the
+brutal cock-fighter, who knows well that he can improve his breed by
+careful selection of the best cocks.  How low in the scale of nature this
+law of battle descends, I know not; male alligators have been described as
+fighting, bellowing, and whirling round, like Indians in a war-dance, for
+the possession of the females; male salmons have been seen fighting all day
+long; male stag-beetles often bear wounds from the huge mandibles of other
+males.  The war is, perhaps, severest between the males of polygamous
+animals, and these seem oftenest provided with special weapons.  The males
+of carnivorous animals are already well armed; though to them and to
+others, special means of defence may be given through means of sexual
+selection, as the mane to the lion, the shoulder-pad to the boar, and the
+hooked jaw to the male salmon; for the shield may be as important for
+victory, as the sword or spear.
+</para>
+
+<para>
+Amongst birds, the contest is often of a more peaceful character.  All
+those who have attended to the subject, believe that there is the severest
+rivalry between the males of many species to attract by singing the
+females.  The rock-thrush of Guiana, birds of Paradise, and some others,
+congregate; and successive males display their gorgeous plumage and perform
+strange antics before the females, which standing by as spectators, at last
+choose the most attractive partner.  Those who have closely attended to
+birds in confinement well know that they often take individual preferences
+and dislikes:  thus Sir R. Heron has described how one pied peacock was
+eminently attractive to all his hen birds.  It may appear childish to
+attribute any effect to such apparently weak means:  I cannot here enter on
+the details necessary to support this view; but if man can in a short time
+give elegant carriage and beauty to his bantams, according to his standard
+of beauty, I can see no good reason to doubt that female birds, by
+selecting, during thousands of generations, the most melodious or beautiful
+males, according to their standard of beauty, might produce a marked
+effect.  I strongly suspect that some well-known laws with respect to the
+plumage of male and female birds, in comparison with the plumage of the
+young, can be explained on the view of plumage having been chiefly modified
+by sexual selection, acting when the birds have come to the breeding age or
+during the breeding season; the modifications thus produced being inherited
+at corresponding ages or seasons, either by the males alone, or by the
+males and females; but I have not space here to enter on this subject.
+</para>
+
+<para>
+Thus it is, as I believe, that when the males and females of any animal
+have the same general habits of life, but differ in structure, colour, or
+ornament, such differences have been mainly caused by sexual selection;
+that is, individual males have had, in successive generations, some slight
+advantage over other males, in their weapons, means of defence, or charms;
+and have transmitted these advantages to their male offspring.  Yet, I
+would not wish to attribute all such sexual differences to this agency: 
+for we see peculiarities arising and becoming attached to the male sex in
+our domestic animals (as the wattle in male carriers, horn-like
+protuberances in the cocks of certain fowls, &amp;c.), which we cannot believe
+to be either useful to the males in battle, or attractive to the females. 
+We see analogous cases under nature, for instance, the tuft of hair on the
+breast of the turkey-cock, which can hardly be either useful or ornamental
+to this bird;--indeed, had the tuft appeared under domestication, it would
+have been called a monstrosity.
+</para>
+
+<para>
+
+Illustrations of the action of Natural Selection. -- In order to make it
+clear how, as I believe, natural selection acts, I must beg permission to
+give one or two imaginary illustrations.  Let us take the case of a wolf,
+which preys on various animals, securing some by craft, some by strength,
+and some by fleetness; and let us suppose that the fleetest prey, a deer
+for instance, had from any change in the country increased in numbers, or
+that other prey had decreased in numbers, during that season of the year
+when the wolf is hardest pressed for food.  I can under such circumstances
+see no reason to doubt that the swiftest and slimmest wolves would have the
+best chance of surviving, and so be preserved or selected,--provided always
+that they retained strength to master their prey at this or at some other
+period of the year, when they might be compelled to prey on other animals. 
+I can see no more reason to doubt this, than that man can improve the
+fleetness of his greyhounds by careful and methodical selection, or by that
+unconscious selection which results from each man trying to keep the best
+dogs without any thought of modifying the breed.
+</para>
+
+<para>
+Even without any change in the proportional numbers of the animals on which
+our wolf preyed, a cub might be born with an innate tendency to pursue
+certain kinds of prey.  Nor can this be thought very improbable; for we
+often observe great differences in the natural tendencies of our domestic
+animals; one cat, for instance, taking to catch rats, another mice; one
+cat, according to Mr. St. John, bringing home winged game, another hares or
+rabbits, and another hunting on marshy ground and almost nightly catching
+woodcocks or snipes.  The tendency to catch rats rather than mice is known
+to be inherited.  Now, if any slight innate change of habit or of structure
+benefited an individual wolf, it would have the best chance of surviving
+and of leaving offspring.  Some of its young would probably inherit the
+same habits or structure, and by the repetition of this process, a new
+variety might be formed which would either supplant or coexist with the
+parent-form of wolf.  Or, again, the wolves inhabiting a mountainous
+district, and those frequenting the lowlands, would naturally be forced to
+hunt different prey; and from the continued preservation of the individuals
+best fitted for the two sites, two varieties might slowly be formed.  These
+varieties would cross and blend where they met; but to this subject of
+intercrossing we shall soon have to return.  I may add, that, according to
+Mr. Pierce, there are two varieties of the wolf inhabiting the Catskill
+Mountains in the United States, one with a light greyhound-like form, which
+pursues deer, and the other more bulky, with shorter legs, which more
+frequently attacks the shepherd's flocks.
+</para>
+
+<para>
+Let us now take a more complex case.  Certain plants excrete a sweet juice,
+apparently for the sake of eliminating something injurious from their sap: 
+this is effected by glands at the base of the stipules in some Leguminosae,
+and at the back of the leaf of the common laurel.  This juice, though small
+in quantity, is greedily sought by insects.  Let us now suppose a little
+sweet juice or nectar to be excreted by the inner bases of the petals of a
+flower.  In this case insects in seeking the nectar would get dusted with
+pollen, and would certainly often transport the pollen from one flower to
+the stigma of another flower.  The flowers of two distinct individuals of
+the same species would thus get crossed; and the act of crossing, we have
+good reason to believe (as will hereafter be more fully alluded to), would
+produce very vigorous seedlings, which consequently would have the best
+chance of flourishing and surviving.  Some of these seedlings would
+probably inherit the nectar-excreting power.  Those individual flowers
+which had the largest glands or nectaries, and which excreted most nectar,
+would be oftenest visited by insects, and would be oftenest crossed; and so
+in the long-run would gain the upper hand.  Those flowers, also, which had
+their stamens and pistils placed, in relation to the size and habits of the
+particular insects which visited them, so as to favour in any degree the
+transportal of their pollen from flower to flower, would likewise be
+favoured or selected.  We might have taken the case of insects visiting
+flowers for the sake of collecting pollen instead of nectar; and as pollen
+is formed for the sole object of fertilisation, its destruction appears a
+simple loss to the plant; yet if a little pollen were carried, at first
+occasionally and then habitually, by the pollen-devouring insects from
+flower to flower, and a cross thus effected, although nine-tenths of the
+pollen were destroyed, it might still be a great gain to the plant; and
+those individuals which produced more and more pollen, and had larger and
+larger anthers, would be selected.
+</para>
+
+<para>
+When our plant, by this process of the continued preservation or natural
+selection of more and more attractive flowers, had been rendered highly
+attractive to insects, they would, unintentionally on their part, regularly
+carry pollen from flower to flower; and that they can most effectually do
+this, I could easily show by many striking instances.  I will give only
+one--not as a very striking case, but as likewise illustrating one step in
+the separation of the sexes of plants, presently to be alluded to.  Some
+holly-trees bear only male flowers, which have four stamens producing
+rather a small quantity of pollen, and a rudimentary pistil; other
+holly-trees bear only female flowers; these have a full-sized pistil, and
+four stamens with shrivelled anthers, in which not a grain of pollen can be
+detected.  Having found a female tree exactly sixty yards from a male tree,
+I put the stigmas of twenty flowers, taken from different branches, under
+the microscope, and on all, without exception, there were pollen-grains,
+and on some a profusion of pollen.  As the wind had set for several days
+from the female to the male tree, the pollen could not thus have been
+carried.  The weather had been cold and boisterous, and therefore not
+favourable to bees, nevertheless every female flower which I examined had
+been effectually fertilised by the bees, accidentally dusted with pollen,
+having flown from tree to tree in search of nectar.  But to return to our
+imaginary case:  as soon as the plant had been rendered so highly
+attractive to insects that pollen was regularly carried from flower to
+flower, another process might commence.  No naturalist doubts the advantage
+of what has been called the 'physiological division of labour;' hence we
+may believe that it would be advantageous to a plant to produce stamens
+alone in one flower or on one whole plant, and pistils alone in another
+flower or on another plant.  In plants under culture and placed under new
+conditions of life, sometimes the male organs and sometimes the female
+organs become more or less impotent; now if we suppose this to occur in
+ever so slight a degree under nature, then as pollen is already carried
+regularly from flower to flower, and as a more complete separation of the
+sexes of our plant would be advantageous on the principle of the division
+of labour, individuals with this tendency more and more increased, would be
+continually favoured or selected, until at last a complete separation of
+the sexes would be effected.
+</para>
+
+<para>
+Let us now turn to the nectar-feeding insects in our imaginary case:  we
+may suppose the plant of which we have been slowly increasing the nectar by
+continued selection, to be a common plant; and that certain insects
+depended in main part on its nectar for food.  I could give many facts,
+showing how anxious bees are to save time; for instance, their habit of
+cutting holes and sucking the nectar at the bases of certain flowers, which
+they can, with a very little more trouble, enter by the mouth.  Bearing
+such facts in mind, I can see no reason to doubt that an accidental
+deviation in the size and form of the body, or in the curvature and length
+of the proboscis, &amp;c., far too slight to be appreciated by us, might profit
+a bee or other insect, so that an individual so characterised would be able
+to obtain its food more quickly, and so have a better chance of living and
+leaving descendants.  Its descendants would probably inherit a tendency to
+a similar slight deviation of structure.  The tubes of the corollas of the
+common red and incarnate clovers (Trifolium pratense and incarnatum) do not
+on a hasty glance appear to differ in length; yet the hive-bee can easily
+suck the nectar out of the incarnate clover, but not out of the common red
+clover, which is visited by humble-bees alone; so that whole fields of the
+red clover offer in vain an abundant supply of precious nectar to the
+hive-bee.  Thus it might be a great advantage to the hive-bee to have a
+slightly longer or differently constructed proboscis.  On the other hand, I
+have found by experiment that the fertility of clover greatly depends on
+bees visiting and moving parts of the corolla, so as to push the pollen on
+to the stigmatic surface.  Hence, again, if humble-bees were to become rare
+in any country, it might be a great advantage to the red clover to have a
+shorter or more deeply divided tube to its corolla, so that the hive-bee
+could visit its flowers.  Thus I can understand how a flower and a bee
+might slowly become, either simultaneously or one after the other, modified
+and adapted in the most perfect manner to each other, by the continued
+preservation of individuals presenting mutual and slightly favourable
+deviations of structure.
+</para>
+
+<para>
+I am well aware that this doctrine of natural selection, exemplified in the
+above imaginary instances, is open to the same objections which were at
+first urged against Sir Charles Lyell's noble views on 'the modern changes
+of the earth, as illustrative of geology;' but we now very seldom hear the
+action, for instance, of the coast-waves, called a trifling and
+insignificant cause, when applied to the excavation of gigantic valleys or
+to the formation of the longest lines of inland cliffs.  Natural selection
+can act only by the preservation and accumulation of infinitesimally small
+inherited modifications, each profitable to the preserved being; and as
+modern geology has almost banished such views as the excavation of a great
+valley by a single diluvial wave, so will natural selection, if it be a
+true principle, banish the belief of the continued creation of new organic
+beings, or of any great and sudden modification in their structure.
+</para>
+
+<para>
+On the Intercrossing of Individuals. -- I must here introduce a short
+digression.  In the case of animals and plants with separated sexes, it is
+of course obvious that two individuals must always unite for each birth;
+but in the case of hermaphrodites this is far from obvious.  Nevertheless I
+am strongly inclined to believe that with all hermaphrodites two
+individuals, either occasionally or habitually, concur for the reproduction
+of their kind.  This view, I may add, was first suggested by Andrew Knight. 
+We shall presently see its importance; but I must here treat the subject
+with extreme brevity, though I have the materials prepared for an ample
+discussion.  All vertebrate animals, all insects, and some other large
+groups of animals, pair for each birth.  Modern research has much
+diminished the number of supposed hermaphrodites, and of real
+hermaphrodites a large number pair; that is, two individuals regularly
+unite for reproduction, which is all that concerns us.  But still there are
+many hermaphrodite animals which certainly do not habitually pair, and a
+vast majority of plants are hermaphrodites.  What reason, it may be asked,
+is there for supposing in these cases that two individuals ever concur in
+reproduction?  As it is impossible here to enter on details, I must trust
+to some general considerations alone.
+</para>
+
+<para>
+In the first place, I have collected so large a body of facts, showing, in
+accordance with the almost universal belief of breeders, that with animals
+and plants a cross between different varieties, or between individuals of
+the same variety but of another strain, gives vigour and fertility to the
+offspring; and on the other hand, that close interbreeding diminishes
+vigour and fertility; that these facts alone incline me to believe that it
+is a general law of nature (utterly ignorant though we be of the meaning of
+the law) that no organic being self-fertilises itself for an eternity of
+generations; but that a cross with another individual is
+occasionally--perhaps at very long intervals--indispensable.
+</para>
+
+<para>
+On the belief that this is a law of nature, we can, I think, understand
+several large classes of facts, such as the following, which on any other
+view are inexplicable.  Every hybridizer knows how unfavourable exposure to
+wet is to the fertilisation of a flower, yet what a multitude of flowers
+have their anthers and stigmas fully exposed to the weather! but if an
+occasional cross be indispensable, the fullest freedom for the entrance of
+pollen from another individual will explain this state of exposure, more
+especially as the plant's own anthers and pistil generally stand so close
+together that self-fertilisation seems almost inevitable.  Many flowers, on
+the other hand, have their organs of fructification closely enclosed, as in
+the great papilionaceous or pea-family; but in several, perhaps in all,
+such flowers, there is a very curious adaptation between the structure of
+the flower and the manner in which bees suck the nectar; for, in doing
+this, they either push the flower's own pollen on the stigma, or bring
+pollen from another flower.  So necessary are the visits of bees to
+papilionaceous flowers, that I have found, by experiments published
+elsewhere, that their fertility is greatly diminished if these visits be
+prevented.  Now, it is scarcely possible that bees should fly from flower
+to flower, and not carry pollen from one to the other, to the great good,
+as I believe, of the plant.  Bees will act like a camel-hair pencil, and it
+is quite sufficient just to touch the anthers of one flower and then the
+stigma of another with the same brush to ensure fertilisation; but it must
+not be supposed that bees would thus produce a multitude of hybrids between
+distinct species; for if you bring on the same brush a plant's own pollen
+and pollen from another species, the former will have such a prepotent
+effect, that it will invariably and completely destroy, as has been shown
+by Gartner, any influence from the foreign pollen.
+</para>
+
+<para>
+When the stamens of a flower suddenly spring towards the pistil, or slowly
+move one after the other towards it, the contrivance seems adapted solely
+to ensure self-fertilisation; and no doubt it is useful for this end:  but,
+the agency of insects is often required to cause the stamens to spring
+forward, as Kolreuter has shown to be the case with the barberry; and
+curiously in this very genus, which seems to have a special contrivance for
+self-fertilisation, it is well known that if very closely-allied forms or
+varieties are planted near each other, it is hardly possible to raise pure
+seedlings, so largely do they naturally cross.  In many other cases, far
+from there being any aids for self-fertilisation, there are special
+contrivances, as I could show from the writings of C. C. Sprengel and from
+my own observations, which effectually prevent the stigma receiving pollen
+from its own flower:  for instance, in Lobelia fulgens, there is a really
+beautiful and elaborate contrivance by which every one of the infinitely
+numerous pollen-granules are swept out of the conjoined anthers of each
+flower, before the stigma of that individual flower is ready to receive
+them; and as this flower is never visited, at least in my garden, by
+insects, it never sets a seed, though by placing pollen from one flower on
+the stigma of another, I raised plenty of seedlings; and whilst another
+species of Lobelia growing close by, which is visited by bees, seeds
+freely.  In very many other cases, though there be no special mechanical
+contrivance to prevent the stigma of a flower receiving its own pollen,
+yet, as C. C. Sprengel has shown, and as I can confirm, either the anthers
+burst before the stigma is ready for fertilisation, or the stigma is ready
+before the pollen of that flower is ready, so that these plants have in
+fact separated sexes, and must habitually be crossed.  How strange are
+these facts!  How strange that the pollen and stigmatic surface of the same
+flower, though placed so close together, as if for the very purpose of
+self-fertilisation, should in so many cases be mutually useless to each
+other!  How simply are these facts explained on the view of an occasional
+cross with a distinct individual being advantageous or indispensable!
+</para>
+
+<para>
+If several varieties of the cabbage, radish, onion, and of some other
+plants, be allowed to seed near each other, a large majority, as I have
+found, of the seedlings thus raised will turn out mongrels:  for instance,
+I raised 233 seedling cabbages from some plants of different varieties
+growing near each other, and of these only 78 were true to their kind, and
+some even of these were not perfectly true.  Yet the pistil of each
+cabbage-flower is surrounded not only by its own six stamens, but by those
+of the many other flowers on the same plant.  How, then, comes it that such
+a vast number of the seedlings are mongrelized?  I suspect that it must
+arise from the pollen of a distinct variety having a prepotent effect over
+a flower's own pollen; and that this is part of the general law of good
+being derived from the intercrossing of distinct individuals of the same
+species.  When distinct species are crossed the case is directly the
+reverse, for a plant's own pollen is always prepotent over foreign pollen;
+but to this subject we shall return in a future chapter.
+</para>
+
+<para>
+In the case of a gigantic tree covered with innumerable flowers, it may be
+objected that pollen could seldom be carried from tree to tree, and at most
+only from flower to flower on the same tree, and that flowers on the same
+tree can be considered as distinct individuals only in a limited sense.  I
+believe this objection to be valid, but that nature has largely provided
+against it by giving to trees a strong tendency to bear flowers with
+separated sexes.  When the sexes are separated, although the male and
+female flowers may be produced on the same tree, we can see that pollen
+must be regularly carried from flower to flower; and this will give a
+better chance of pollen being occasionally carried from tree to tree.  That
+trees belonging to all Orders have their sexes more often separated than
+other plants, I find to be the case in this country; and at my request Dr.
+Hooker tabulated the trees of New Zealand, and Dr. Asa Gray those of the
+United States, and the result was as I anticipated.  On the other hand, Dr.
+Hooker has recently informed me that he finds that the rule does not hold
+in Australia; and I have made these few remarks on the sexes of trees
+simply to call attention to the subject.
+</para>
+
+<para>
+Turning for a very brief space to animals:  on the land there are some
+hermaphrodites, as land-mollusca and earth-worms; but these all pair.  As
+yet I have not found a single case of a terrestrial animal which fertilises
+itself.  We can understand this remarkable fact, which offers so strong a
+contrast with terrestrial plants, on the view of an occasional cross being
+indispensable, by considering the medium in which terrestrial animals live,
+and the nature of the fertilising element; for we know of no means,
+analogous to the action of insects and of the wind in the case of plants,
+by which an occasional cross could be effected with terrestrial animals
+without the concurrence of two individuals.  Of aquatic animals, there are
+many self-fertilising hermaphrodites; but here currents in the water offer
+an obvious means for an occasional cross.  And, as in the case of flowers,
+I have as yet failed, after consultation with one of the highest
+authorities, namely, Professor Huxley, to discover a single case of an
+hermaphrodite animal with the organs of reproduction so perfectly enclosed
+within the body, that access from without and the occasional influence of a
+distinct individual can be shown to be physically impossible.  Cirripedes
+long appeared to me to present a case of very great difficulty under this
+point of view; but I have been enabled, by a fortunate chance, elsewhere to
+prove that two individuals, though both are self-fertilising
+hermaphrodites, do sometimes cross.
+</para>
+
+<para>
+It must have struck most naturalists as a strange anomaly that, in the case
+of both animals and plants, species of the same family and even of the same
+genus, though agreeing closely with each other in almost their whole
+organisation, yet are not rarely, some of them hermaphrodites, and some of
+them unisexual.  But if, in fact, all hermaphrodites do occasionally
+intercross with other individuals, the difference between hermaphrodites
+and unisexual species, as far as function is concerned, becomes very small.
+</para>
+
+<para>
+From these several considerations and from the many special facts which I
+have collected, but which I am not here able to give, I am strongly
+inclined to suspect that, both in the vegetable and animal kingdoms, an
+occasional intercross with a distinct individual is a law of nature.  I am
+well aware that there are, on this view, many cases of difficulty, some of
+which I am trying to investigate.  Finally then, we may conclude that in
+many organic beings, a cross between two individuals is an obvious
+necessity for each birth; in many others it occurs perhaps only at long
+intervals; but in none, as I suspect, can self-fertilisation go on for
+perpetuity.
+</para>
+
+<para>
+Circumstances favourable to Natural Selection. -- This is an extremely
+intricate subject.  A large amount of inheritable and diversified
+variability is favourable, but I believe mere individual differences
+suffice for the work.  A large number of individuals, by giving a better
+chance for the appearance within any given period of profitable variations,
+will compensate for a lesser amount of variability in each individual, and
+is, I believe, an extremely important element of success.  Though nature
+grants vast periods of time for the work of natural selection, she does not
+grant an indefinite period; for as all organic beings are striving, it may
+be said, to seize on each place in the economy of nature, if any one
+species does not become modified and improved in a corresponding degree
+with its competitors, it will soon be exterminated.
+</para>
+
+<para>
+In man's methodical selection, a breeder selects for some definite object,
+and free intercrossing will wholly stop his work.  But when many men,
+without intending to alter the breed, have a nearly common standard of
+perfection, and all try to get and breed from the best animals, much
+improvement and modification surely but slowly follow from this unconscious
+process of selection, notwithstanding a large amount of crossing with
+inferior animals.  Thus it will be in nature; for within a confined area,
+with some place in its polity not so perfectly occupied as might be,
+natural selection will always tend to preserve all the individuals varying
+in the right direction, though in different degrees, so as better to fill
+up the unoccupied place.  But if the area be large, its several districts
+will almost certainly present different conditions of life; and then if
+natural selection be modifying and improving a species in the several
+districts, there will be intercrossing with the other individuals of the
+same species on the confines of each.  And in this case the effects of
+intercrossing can hardly be counterbalanced by natural selection always
+tending to modify all the individuals in each district in exactly the same
+manner to the conditions of each; for in a continuous area, the conditions
+will generally graduate away insensibly from one district to another.  The
+intercrossing will most affect those animals which unite for each birth,
+which wander much, and which do not breed at a very quick rate.  Hence in
+animals of this nature, for instance in birds, varieties will generally be
+confined to separated countries; and this I believe to be the case.  In
+hermaphrodite organisms which cross only occasionally, and likewise in
+animals which unite for each birth, but which wander little and which can
+increase at a very rapid rate, a new and improved variety might be quickly
+formed on any one spot, and might there maintain itself in a body, so that
+whatever intercrossing took place would be chiefly between the individuals
+of the same new variety.  A local variety when once thus formed might
+subsequently slowly spread to other districts.  On the above principle,
+nurserymen always prefer getting seed from a large body of plants of the
+same variety, as the chance of intercrossing with other varieties is thus
+lessened.
+</para>
+
+<para>
+Even in the case of slow-breeding animals, which unite for each birth, we
+must not overrate the effects of intercrosses in retarding natural
+selection; for I can bring a considerable catalogue of facts, showing that
+within the same area, varieties of the same animal can long remain
+distinct, from haunting different stations, from breeding at slightly
+different seasons, or from varieties of the same kind preferring to pair
+together.
+</para>
+
+<para>
+Intercrossing plays a very important part in nature in keeping the
+individuals of the same species, or of the same variety, true and uniform
+in character.  It will obviously thus act far more efficiently with those
+animals which unite for each birth; but I have already attempted to show
+that we have reason to believe that occasional intercrosses take place with
+all animals and with all plants.  Even if these take place only at long
+intervals, I am convinced that the young thus produced will gain so much in
+vigour and fertility over the offspring from long-continued
+self-fertilisation, that they will have a better chance of surviving and
+propagating their kind; and thus, in the long run, the influence of
+intercrosses, even at rare intervals, will be great.  If there exist
+organic beings which never intercross, uniformity of character can be
+retained amongst them, as long as their conditions of life remain the same,
+only through the principle of inheritance, and through natural selection
+destroying any which depart from the proper type; but if their conditions
+of life change and they undergo modification, uniformity of character can
+be given to their modified offspring, solely by natural selection
+preserving the same favourable variations.
+</para>
+
+<para>
+Isolation, also, is an important element in the process of natural
+selection.  In a confined or isolated area, if not very large, the organic
+and inorganic conditions of life will generally be in a great degree
+uniform; so that natural selection will tend to modify all the individuals
+of a varying species throughout the area in the same manner in relation to
+the same conditions.  Intercrosses, also, with the individuals of the same
+species, which otherwise would have inhabited the surrounding and
+differently circumstanced districts, will be prevented.  But isolation
+probably acts more efficiently in checking the immigration of better
+adapted organisms, after any physical change, such as of climate or
+elevation of the land, &amp;c.; and thus new places in the natural economy of
+the country are left open for the old inhabitants to struggle for, and
+become adapted to, through modifications in their structure and
+constitution.  Lastly, isolation, by checking immigration and consequently
+competition, will give time for any new variety to be slowly improved; and
+this may sometimes be of importance in the production of new species.  If,
+however, an isolated area be very small, either from being surrounded by
+barriers, or from having very peculiar physical conditions, the total
+number of the individuals supported on it will necessarily be very small;
+and fewness of individuals will greatly retard the production of new
+species through natural selection, by decreasing the chance of the
+appearance of favourable variations.
+</para>
+
+<para>
+If we turn to nature to test the truth of these remarks, and look at any
+small isolated area, such as an oceanic island, although the total number
+of the species inhabiting it, will be found to be small, as we shall see in
+our chapter on geographical distribution; yet of these species a very large
+proportion are endemic,--that is, have been produced there, and nowhere
+else.  Hence an oceanic island at first sight seems to have been highly
+favourable for the production of new species.  But we may thus greatly
+deceive ourselves, for to ascertain whether a small isolated area, or a
+large open area like a continent, has been most favourable for the
+production of new organic forms, we ought to make the comparison within
+equal times; and this we are incapable of doing.
+</para>
+
+<para>
+Although I do not doubt that isolation is of considerable importance in the
+production of new species, on the whole I am inclined to believe that
+largeness of area is of more importance, more especially in the production
+of species, which will prove capable of enduring for a long period, and of
+spreading widely.  Throughout a great and open area, not only will there be
+a better chance of favourable variations arising from the large number of
+individuals of the same species there supported, but the conditions of life
+are infinitely complex from the large number of already existing species;
+and if some of these many species become modified and improved, others will
+have to be improved in a corresponding degree or they will be exterminated. 
+Each new form, also, as soon as it has been much improved, will be able to
+spread over the open and continuous area, and will thus come into
+competition with many others.  Hence more new places will be formed, and
+the competition to fill them will be more severe, on a large than on a
+small and isolated area.  Moreover, great areas, though now continuous,
+owing to oscillations of level, will often have recently existed in a
+broken condition, so that the good effects of isolation will generally, to
+a certain extent, have concurred.  Finally, I conclude that, although small
+isolated areas probably have been in some respects highly favourable for
+the production of new species, yet that the course of modification will
+generally have been more rapid on large areas; and what is more important,
+that the new forms produced on large areas, which already have been
+victorious over many competitors, will be those that will spread most
+widely, will give rise to most new varieties and species, and will thus
+play an important part in the changing history of the organic world.
+</para>
+
+<para>
+We can, perhaps, on these views, understand some facts which will be again
+alluded to in our chapter on geographical distribution; for instance, that
+the productions of the smaller continent of Australia have formerly
+yielded, and apparently are now yielding, before those of the larger
+Europaeo-Asiatic area.  Thus, also, it is that continental productions have
+everywhere become so largely naturalised on islands.  On a small island,
+the race for life will have been less severe, and there will have been less
+modification and less extermination.  Hence, perhaps, it comes that the
+flora of Madeira, according to Oswald Heer, resembles the extinct tertiary
+flora of Europe.  All fresh-water basins, taken together, make a small area
+compared with that of the sea or of the land; and, consequently, the
+competition between fresh-water productions will have been less severe than
+elsewhere; new forms will have been more slowly formed, and old forms more
+slowly exterminated.  And it is in fresh water that we find seven genera of
+Ganoid fishes, remnants of a once preponderant order:  and in fresh water
+we find some of the most anomalous forms now known in the world, as the
+Ornithorhynchus and Lepidosiren, which, like fossils, connect to a certain
+extent orders now widely separated in the natural scale.  These anomalous
+forms may almost be called living fossils; they have endured to the present
+day, from having inhabited a confined area, and from having thus been
+exposed to less severe competition.
+</para>
+
+<para>
+To sum up the circumstances favourable and unfavourable to natural
+selection, as far as the extreme intricacy of the subject permits.  I
+conclude, looking to the future, that for terrestrial productions a large
+continental area, which will probably undergo many oscillations of level,
+and which consequently will exist for long periods in a broken condition,
+will be the most favourable for the production of many new forms of life,
+likely to endure long and to spread widely.  For the area will first have
+existed as a continent, and the inhabitants, at this period numerous in
+individuals and kinds, will have been subjected to very severe competition. 
+When converted by subsidence into large separate islands, there will still
+exist many individuals of the same species on each island:  intercrossing
+on the confines of the range of each species will thus be checked:  after
+physical changes of any kind, immigration will be prevented, so that new
+places in the polity of each island will have to be filled up by
+modifications of the old inhabitants; and time will be allowed for the
+varieties in each to become well modified and perfected.  When, by renewed
+elevation, the islands shall be re-converted into a continental area, there
+will again be severe competition:  the most favoured or improved varieties
+will be enabled to spread:  there will be much extinction of the less
+improved forms, and the relative proportional numbers of the various
+inhabitants of the renewed continent will again be changed; and again there
+will be a fair field for natural selection to improve still further the
+inhabitants, and thus produce new species.
+</para>
+
+<para>
+That natural selection will always act with extreme slowness, I fully
+admit.  Its action depends on there being places in the polity of nature,
+which can be better occupied by some of the inhabitants of the country
+undergoing modification of some kind.  The existence of such places will
+often depend on physical changes, which are generally very slow, and on the
+immigration of better adapted forms having been checked.  But the action of
+natural selection will probably still oftener depend on some of the
+inhabitants becoming slowly modified; the mutual relations of many of the
+other inhabitants being thus disturbed.  Nothing can be effected, unless
+favourable variations occur, and variation itself is apparently always a
+very slow process.  The process will often be greatly retarded by free
+intercrossing.  Many will exclaim that these several causes are amply
+sufficient wholly to stop the action of natural selection.  I do not
+believe so.  On the other hand, I do believe that natural selection will
+always act very slowly, often only at long intervals of time, and generally
+on only a very few of the inhabitants of the same region at the same time. 
+I further believe, that this very slow, intermittent action of natural
+selection accords perfectly well with what geology tells us of the rate and
+manner at which the inhabitants of this world have changed.
+</para>
+
+<para>
+Slow though the process of selection may be, if feeble man can do much by
+his powers of artificial selection, I can see no limit to the amount of
+change, to the beauty and infinite complexity of the coadaptations between
+all organic beings, one with another and with their physical conditions of
+life, which may be effected in the long course of time by nature's power of
+selection.
+</para>
+
+<para>
+Extinction. -- This subject will be more fully discussed in our chapter on
+Geology; but it must be here alluded to from being intimately connected
+with natural selection.  Natural selection acts solely through the
+preservation of variations in some way advantageous, which consequently
+endure.  But as from the high geometrical powers of increase of all organic
+beings, each area is already fully stocked with inhabitants, it follows
+that as each selected and favoured form increases in number, so will the
+less favoured forms decrease and become rare.  Rarity, as geology tells us,
+is the precursor to extinction.  We can, also, see that any form
+represented by few individuals will, during fluctuations in the seasons or
+in the number of its enemies, run a good chance of utter extinction.  But
+we may go further than this; for as new forms are continually and slowly
+being produced, unless we believe that the number of specific forms goes on
+perpetually and almost indefinitely increasing, numbers inevitably must
+become extinct.  That the number of specific forms has not indefinitely
+increased, geology shows us plainly; and indeed we can see reason why they
+should not have thus increased, for the number of places in the polity of
+nature is not indefinitely great,--not that we have any means of knowing
+that any one region has as yet got its maximum of species.  Probably no
+region is as yet fully stocked, for at the Cape of Good Hope, where more
+species of plants are crowded together than in any other quarter of the
+world, some foreign plants have become naturalised, without causing, as far
+as we know, the extinction of any natives.
+</para>
+
+<para>
+Furthermore, the species which are most numerous in individuals will have
+the best chance of producing within any given period favourable variations. 
+We have evidence of this, in the facts given in the second chapter, showing
+that it is the common species which afford the greatest number of recorded
+varieties, or incipient species.  Hence, rare species will be less quickly
+modified or improved within any given period, and they will consequently be
+beaten in the race for life by the modified descendants of the commoner
+species.
+</para>
+
+<para>
+From these several considerations I think it inevitably follows, that as
+new species in the course of time are formed through natural selection,
+others will become rarer and rarer, and finally extinct.  The forms which
+stand in closest competition with those undergoing modification and
+improvement, will naturally suffer most.  And we have seen in the chapter
+on the Struggle for Existence that it is the most closely-allied
+forms,--varieties of the same species, and species of the same genus or of
+related genera,--which, from having nearly the same structure,
+constitution, and habits, generally come into the severest competition with
+each other.  Consequently, each new variety or species, during the progress
+of its formation, will generally press hardest on its nearest kindred, and
+tend to exterminate them.  We see the same process of extermination amongst
+our domesticated productions, through the selection of improved forms by
+man.  Many curious instances could be given showing how quickly new breeds
+of cattle, sheep, and other animals, and varieties of flowers, take the
+place of older and inferior kinds.  In Yorkshire, it is historically known
+that the ancient black cattle were displaced by the long-horns, and that
+these 'were swept away by the short-horns' (I quote the words of an
+agricultural writer) 'as if by some murderous pestilence.'
+</para>
+
+<para>
+Divergence of Character. -- The principle, which I have designated by this
+term, is of high importance on my theory, and explains, as I believe,
+several important facts.  In the first place, varieties, even
+strongly-marked ones, though having somewhat of the character of
+species--as is shown by the hopeless doubts in many cases how to rank
+them--yet certainly differ from each other far less than do good and
+distinct species.  Nevertheless, according to my view, varieties are
+species in the process of formation, or are, as I have called them,
+incipient species.  How, then, does the lesser difference between varieties
+become augmented into the greater difference between species?  That this
+does habitually happen, we must infer from most of the innumerable species
+throughout nature presenting well-marked differences; whereas varieties,
+the supposed prototypes and parents of future well-marked species, present
+slight and ill-defined differences.  Mere chance, as we may call it, might
+cause one variety to differ in some character from its parents, and the
+offspring of this variety again to differ from its parent in the very same
+character and in a greater degree; but this alone would never account for
+so habitual and large an amount of difference as that between varieties of
+the same species and species of the same genus.
+</para>
+
+<para>
+As has always been my practice, let us seek light on this head from our
+domestic productions.  We shall here find something analogous.  A fancier
+is struck by a pigeon having a slightly shorter beak; another fancier is
+struck by a pigeon having a rather longer beak; and on the acknowledged
+principle that 'fanciers do not and will not admire a medium standard, but
+like extremes,' they both go on (as has actually occurred with
+tumbler-pigeons) choosing and breeding from birds with longer and longer
+beaks, or with shorter and shorter beaks.  Again, we may suppose that at an
+early period one man preferred swifter horses; another stronger and more
+bulky horses.  The early differences would be very slight; in the course of
+time, from the continued selection of swifter horses by some breeders, and
+of stronger ones by others, the differences would become greater, and would
+be noted as forming two sub-breeds; finally, after the lapse of centuries,
+the sub-breeds would become converted into two well-established and
+distinct breeds.  As the differences slowly become greater, the inferior
+animals with intermediate characters, being neither very swift nor very
+strong, will have been neglected, and will have tended to disappear.  Here,
+then, we see in man's productions the action of what may be called the
+principle of divergence, causing differences, at first barely appreciable,
+steadily to increase, and the breeds to diverge in character both from each
+other and from their common parent.
+</para>
+
+<para>
+But how, it may be asked, can any analogous principle apply in nature?  I
+believe it can and does apply most efficiently, from the simple
+circumstance that the more diversified the descendants from any one species
+become in structure, constitution, and habits, by so much will they be
+better enabled to seize on many and widely diversified places in the polity
+of nature, and so be enabled to increase in numbers.
+</para>
+
+<para>
+We can clearly see this in the case of animals with simple habits.  Take
+the case of a carnivorous quadruped, of which the number that can be
+supported in any country has long ago arrived at its full average.  If its
+natural powers of increase be allowed to act, it can succeed in increasing
+(the country not undergoing any change in its conditions) only by its
+varying descendants seizing on places at present occupied by other animals: 
+some of them, for instance, being enabled to feed on new kinds of prey,
+either dead or alive; some inhabiting new stations, climbing trees,
+frequenting water, and some perhaps becoming less carnivorous.  The more
+diversified in habits and structure the descendants of our carnivorous
+animal became, the more places they would be enabled to occupy.  What
+applies to one animal will apply throughout all time to all animals--that
+is, if they vary--for otherwise natural selection can do nothing.  So it
+will be with plants.  It has been experimentally proved, that if a plot of
+ground be sown with several distinct genera of grasses, a greater number of
+plants and a greater weight of dry herbage can thus be raised.  The same
+has been found to hold good when first one variety and then several mixed
+varieties of wheat have been sown on equal spaces of ground.  Hence, if any
+one species of grass were to go on varying, and those varieties were
+continually selected which differed from each other in at all the same
+manner as distinct species and genera of grasses differ from each other, a
+greater number of individual plants of this species of grass, including its
+modified descendants, would succeed in living on the same piece of ground. 
+And we well know that each species and each variety of grass is annually
+sowing almost countless seeds; and thus, as it may be said, is striving its
+utmost to increase its numbers.  Consequently, I cannot doubt that in the
+course of many thousands of generations, the most distinct varieties of any
+one species of grass would always have the best chance of succeeding and of
+increasing in numbers, and thus of supplanting the less distinct varieties;
+and varieties, when rendered very distinct from each other, take the rank
+of species.
+</para>
+
+<para>
+The truth of the principle, that the greatest amount of life can be
+supported by great diversification of structure, is seen under many natural
+circumstances.  In an extremely small area, especially if freely open to
+immigration, and where the contest between individual and individual must
+be severe, we always find great diversity in its inhabitants.  For
+instance, I found that a piece of turf, three feet by four in size, which
+had been exposed for many years to exactly the same conditions, supported
+twenty species of plants, and these belonged to eighteen genera and to
+eight orders, which shows how much these plants differed from each other. 
+So it is with the plants and insects on small and uniform islets; and so in
+small ponds of fresh water.  Farmers find that they can raise most food by
+a rotation of plants belonging to the most different orders:  nature
+follows what may be called a simultaneous rotation.  Most of the animals
+and plants which live close round any small piece of ground, could live on
+it (supposing it not to be in any way peculiar in its nature), and may be
+said to be striving to the utmost to live there; but, it is seen, that
+where they come into the closest competition with each other, the
+advantages of diversification of structure, with the accompanying
+differences of habit and constitution, determine that the inhabitants,
+which thus jostle each other most closely, shall, as a general rule, belong
+to what we call different genera and orders.
+</para>
+
+<para>
+The same principle is seen in the naturalisation of plants through man's
+agency in foreign lands.  It might have been expected that the plants which
+have succeeded in becoming naturalised in any land would generally have
+been closely allied to the indigenes; for these are commonly looked at as
+specially created and adapted for their own country.  It might, also,
+perhaps have been expected that naturalised plants would have belonged to a
+few groups more especially adapted to certain stations in their new homes. 
+But the case is very different; and Alph. De Candolle has well remarked in
+his great and admirable work, that floras gain by naturalisation,
+proportionally with the number of the native genera and species, far more
+in new genera than in new species.  To give a single instance:  in the last
+edition of Dr. Asa Gray's 'Manual of the Flora of the Northern United
+States,' 260 naturalised plants are enumerated, and these belong to 162
+genera.  We thus see that these naturalised plants are of a highly
+diversified nature.  They differ, moreover, to a large extent from the
+indigenes, for out of the 162 genera, no less than 100 genera are not there
+indigenous, and thus a large proportional addition is made to the genera of
+these States.
+</para>
+
+<para>
+By considering the nature of the plants or animals which have struggled
+successfully with the indigenes of any country, and have there become
+naturalised, we can gain some crude idea in what manner some of the natives
+would have had to be modified, in order to have gained an advantage over
+the other natives; and we may, I think, at least safely infer that
+diversification of structure, amounting to new generic differences, would
+have been profitable to them.
+</para>
+
+<para>
+The advantage of diversification in the inhabitants of the same region is,
+in fact, the same as that of the physiological division of labour in the
+organs of the same individual body--a subject so well elucidated by Milne
+Edwards.  No physiologist doubts that a stomach by being adapted to digest
+vegetable matter alone, or flesh alone, draws most nutriment from these
+substances.  So in the general economy of any land, the more widely and
+perfectly the animals and plants are diversified for different habits of
+life, so will a greater number of individuals be capable of there
+supporting themselves.  A set of animals, with their organisation but
+little diversified, could hardly compete with a set more perfectly
+diversified in structure.  It may be doubted, for instance, whether the
+Australian marsupials, which are divided into groups differing but little
+from each other, and feebly representing, as Mr. Waterhouse and others have
+remarked, our carnivorous, ruminant, and rodent mammals, could successfully
+compete with these well-pronounced orders.  In the Australian mammals, we
+see the process of diversification in an early and incomplete stage of
+development.
+</para>
+
+<para>
+After the foregoing discussion, which ought to have been much amplified, we
+may, I think, assume that the modified descendants of any one species will
+succeed by so much the better as they become more diversified in structure,
+and are thus enabled to encroach on places occupied by other beings.  Now
+let us see how this principle of great benefit being derived from
+divergence of character, combined with the principles of natural selection
+and of extinction, will tend to act.
+</para>
+
+<para>
+The accompanying diagram will aid us in understanding this rather
+perplexing subject.  Let A to L represent the species of a genus large in
+its own country; these species are supposed to resemble each other in
+unequal degrees, as is so generally the case in nature, and as is
+represented in the diagram by the letters standing at unequal distances.  I
+have said a large genus, because we have seen in the second chapter, that
+on an average more of the species of large genera vary than of small
+genera; and the varying species of the large genera present a greater
+number of varieties.  We have, also, seen that the species, which are the
+commonest and the most widely-diffused, vary more than rare species with
+restricted ranges.  Let (A) be a common, widely-diffused, and varying
+species, belonging to a genus large in its own country.  The little fan of
+diverging dotted lines of unequal lengths proceeding from (A), may
+represent its varying offspring.  The variations are supposed to be
+extremely slight, but of the most diversified nature; they are not supposed
+all to appear simultaneously, but often after long intervals of time; nor
+are they all supposed to endure for equal periods.  Only those variations
+which are in some way profitable will be preserved or naturally selected. 
+And here the importance of the principle of benefit being derived from
+divergence of character comes in; for this will generally lead to the most
+different or divergent variations (represented by the outer dotted lines)
+being preserved and accumulated by natural selection.  When a dotted line
+reaches one of the horizontal lines, and is there marked by a small
+numbered letter, a sufficient amount of variation is supposed to have been
+accumulated to have formed a fairly well-marked variety, such as would be
+thought worthy of record in a systematic work.
+</para>
+
+<para>
+The intervals between the horizontal lines in the diagram, may represent
+each a thousand generations; but it would have been better if each had
+represented ten thousand generations.  After a thousand generations,
+species (A) is supposed to have produced two fairly well-marked varieties,
+namely a1 and m1.  These two varieties will generally continue to be
+exposed to the same conditions which made their parents variable, and the
+tendency to variability is in itself hereditary, consequently they will
+tend to vary, and generally to vary in nearly the same manner as their
+parents varied.  Moreover, these two varieties, being only slightly
+modified forms, will tend to inherit those advantages which made their
+common parent (A) more numerous than most of the other inhabitants of the
+same country; they will likewise partake of those more general advantages
+which made the genus to which the parent-species belonged, a large genus in
+its own country.  And these circumstances we know to be favourable to the
+production of new varieties.
+</para>
+
+<para>
+If, then, these two varieties be variable, the most divergent of their
+variations will generally be preserved during the next thousand
+generations.  And after this interval, variety a1 is supposed in the
+diagram to have produced variety a2, which will, owing to the principle of
+divergence, differ more from (A) than did variety  a1.  Variety m1 is
+supposed to have produced two varieties, namely m2 and s2, differing from
+each other, and more considerably from their common parent (A).  We may
+continue the process by similar steps for any length of time; some of the
+varieties, after each thousand generations, producing only a single
+variety, but in a more and more modified condition, some producing two or
+three varieties, and some failing to produce any.  Thus the varieties or
+modified descendants, proceeding from the common parent (A), will generally
+go on increasing in number and diverging in character.  In the diagram the
+process is represented up to the ten-thousandth generation, and under a
+condensed and simplified form up to the fourteen-thousandth generation.
+</para>
+
+<para>
+But I must here remark that I do not suppose that the process ever goes on
+so regularly as is represented in the diagram, though in itself made
+somewhat irregular.  I am far from thinking that the most divergent
+varieties will invariably prevail and multiply:  a medium form may often
+long endure, and may or may not produce more than one modified descendant;
+for natural selection will always act according to the nature of the places
+which are either unoccupied or not perfectly occupied by other beings; and
+this will depend on infinitely complex relations.  But as a general rule,
+the more diversified in structure the descendants from any one species can
+be rendered, the more places they will be enabled to seize on, and the more
+their modified progeny will be increased.  In our diagram the line of
+succession is broken at regular intervals by small numbered letters marking
+the successive forms which have become sufficiently distinct to be recorded
+as varieties.  But these breaks are imaginary, and might have been inserted
+anywhere, after intervals long enough to have allowed the accumulation of a
+considerable amount of divergent variation.
+</para>
+
+<para>
+As all the modified descendants from a common and widely-diffused species,
+belonging to a large genus, will tend to partake of the same advantages
+which made their parent successful in life, they will generally go on
+multiplying in number as well as diverging in character:  this is
+represented in the diagram by the several divergent branches proceeding
+from (A).  The modified offspring from the later and more highly improved
+branches in the lines of descent, will, it is probable, often take the
+place of, and so destroy, the earlier and less improved branches:  this is
+represented in the diagram by some of the lower branches not reaching to
+the upper horizontal lines.  In some cases I do not doubt that the process
+of modification will be confined to a single line of descent, and the
+number of the descendants will not be increased; although the amount of
+divergent modification may have been increased in the successive
+generations.  This case would be represented in the diagram, if all the
+lines proceeding from (A) were removed, excepting that from a1 to a10.  In
+the same way, for instance, the English race-horse and English pointer have
+apparently both gone on slowly diverging in character from their original
+stocks, without either having given off any fresh branches or races.
+</para>
+
+<para>
+After ten thousand generations, species (A) is supposed to have produced
+three forms, a10, f10, and m10, which, from having diverged in character
+during the successive generations, will have come to differ largely, but
+perhaps unequally, from each other and from their common parent.  If we
+suppose the amount of change between each horizontal line in our diagram to
+be excessively small, these three forms may still be only well-marked
+varieties; or they may have arrived at the doubtful category of
+sub-species; but we have only to suppose the steps in the process of
+modification to be more numerous or greater in amount, to convert these
+three forms into well-defined species:  thus the diagram illustrates the
+steps by which the small differences distinguishing varieties are increased
+into the larger differences distinguishing species.  By continuing the same
+process for a greater number of generations (as shown in the diagram in a
+condensed and simplified manner), we get eight species, marked by the
+letters between a14 and m14, all descended from (A).  Thus, as I believe,
+species are multiplied and genera are formed.
+</para>
+
+<para>
+In a large genus it is probable that more than one species would vary.  In
+the diagram I have assumed that a second species (I) has produced, by
+analogous steps, after ten thousand generations, either two well-marked
+varieties (w10 and z10) or two species, according to the amount of change
+supposed to be represented between the horizontal lines.  After fourteen
+thousand generations, six new species, marked by the letters n14 to z14,
+are supposed to have been produced.  In each genus, the species, which are
+already extremely different in character, will generally tend to produce
+the greatest number of modified descendants; for these will have the best
+chance of filling new and widely different places in the polity of nature: 
+hence in the diagram I have chosen the extreme species (A), and the nearly
+extreme species (I), as those which have largely varied, and have given
+rise to new varieties and species.  The other nine species (marked by
+capital letters) of our original genus, may for a long period continue
+transmitting unaltered descendants; and this is shown in the diagram by the
+dotted lines not prolonged far upwards from want of space.
+</para>
+
+<para>
+But during the process of modification, represented in the diagram, another
+of our principles, namely that of extinction, will have played an important
+part.  As in each fully stocked country natural selection necessarily acts
+by the selected form having some advantage in the struggle for life over
+other forms, there will be a constant tendency in the improved descendants
+of any one species to supplant and exterminate in each stage of descent
+their predecessors and their original parent.  For it should be remembered
+that the competition will generally be most severe between those forms
+which are most nearly related to each other in habits, constitution, and
+structure.  Hence all the intermediate forms between the earlier and later
+states, that is between the less and more improved state of a species, as
+well as the original parent-species itself, will generally tend to become
+extinct.  So it probably will be with many whole collateral lines of
+descent, which will be conquered by later and improved lines of descent. 
+If, however, the modified offspring of a species get into some distinct
+country, or become quickly adapted to some quite new station, in which
+child and parent do not come into competition, both may continue to exist.
+</para>
+
+<para>
+If then our diagram be assumed to represent a considerable amount of
+modification, species (A) and all the earlier varieties will have become
+extinct, having been replaced by eight new species (a14 to m14); and (I)
+will have been replaced by six (n14 to z14) new species.
+</para>
+
+<para>
+But we may go further than this.  The original species of our genus were
+supposed to resemble each other in unequal degrees, as is so generally the
+case in nature; species (A) being more nearly related to B, C, and D, than
+to the other species; and species (I) more to G, H, K, L, than to the
+others.  These two species (A) and (I), were also supposed to be very
+common and widely diffused species, so that they must originally have had
+some advantage over most of the other species of the genus.  Their modified
+descendants, fourteen in number at the fourteen-thousandth generation, will
+probably have inherited some of the same advantages:  they have also been
+modified and improved in a diversified manner at each stage of descent, so
+as to have become adapted to many related places in the natural economy of
+their country.  It seems, therefore, to me extremely probable that they
+will have taken the places of, and thus exterminated, not only their
+parents (A) and (I), but likewise some of the original species which were
+most nearly related to their parents.  Hence very few of the original
+species will have transmitted offspring to the fourteen-thousandth
+generation.  We may suppose that only one (F), of the two species which
+were least closely related to the other nine original species, has
+transmitted descendants to this late stage of descent.
+</para>
+
+<para>
+The new species in our diagram descended from the original eleven species,
+will now be fifteen in number.  Owing to the divergent tendency of natural
+selection, the extreme amount of difference in character between species
+a14 and z14 will be much greater than that between the most different of
+the original eleven species.  The new species, moreover, will be allied to
+each other in a widely different manner.  Of the eight descendants from (A)
+the three marked a14, q14, p14, will be nearly related from having recently
+branched off from a10; b14 and f14, from having diverged at an earlier
+period from a5, will be in some degree distinct from the three first-named
+species; and lastly, o14, e14, and m14, will be nearly related one to the
+other, but from having diverged at the first commencement of the process of
+modification, will be widely different from the other five species, and may
+constitute a sub-genus or even a distinct genus.  
+</para>
+
+<para>
+The six descendants from (I) will form two sub-genera or even genera.  But
+as the original species (I) differed largely from (A), standing nearly at
+the extreme points of the original genus, the six descendants from (I)
+will, owing to inheritance, differ considerably from the eight descendants
+from (A); the two groups, moreover, are supposed to have gone on diverging
+in different directions.  The intermediate species, also (and this is a
+very important consideration), which connected the original species (A) and
+(I), have all become, excepting (F), extinct, and have left no descendants. 
+Hence the six new species descended from (I), and the eight descended from
+(A), will have to be ranked as very distinct genera, or even as distinct
+sub-families.
+</para>
+
+<para>
+Thus it is, as I believe, that two or more genera are produced by descent,
+with modification, from two or more species of the same genus.  And the two
+or more parent-species are supposed to have descended from some one species
+of an earlier genus.  In our diagram, this is indicated by the broken
+lines, beneath the capital letters, converging in sub-branches downwards
+towards a single point; this point representing a single species, the
+supposed single parent of our several new sub-genera and genera.
+</para>
+
+<para>
+It is worth while to reflect for a moment on the character of the new
+species F14, which is supposed not to have diverged much in character, but
+to have retained the form of (F), either unaltered or altered only in a
+slight degree.  In this case, its affinities to the other fourteen new
+species will be of a curious and circuitous nature.  Having descended from
+a form which stood between the two parent-species (A) and (I), now supposed
+to be extinct and unknown, it will be in some degree intermediate in
+character between the two groups descended from these species.  But as
+these two groups have gone on diverging in character from the type of their
+parents, the new species (F14) will not be directly intermediate between
+them, but rather between types of the two groups; and every naturalist will
+be able to bring some such case before his mind.
+</para>
+
+<para>
+In the diagram, each horizontal line has hitherto been supposed to
+represent a thousand generations, but each may represent a million or
+hundred million generations, and likewise a section of the successive
+strata of the earth's crust including extinct remains.  We shall, when we
+come to our chapter on Geology, have to refer again to this subject, and I
+think we shall then see that the diagram throws light on the affinities of
+extinct beings, which, though generally belonging to the same orders, or
+families, or genera, with those now living, yet are often, in some degree,
+intermediate in character between existing groups; and we can understand
+this fact, for the extinct species lived at very ancient epochs when the
+branching lines of descent had diverged less.
+</para>
+
+<para>
+I see no reason to limit the process of modification, as now explained, to
+the formation of genera alone.  If, in our diagram, we suppose the amount
+of change represented by each successive group of diverging dotted lines to
+be very great, the forms marked a14 to p14, those marked b14 and f14, and
+those marked o14 to m14, will form three very distinct genera.  We shall
+also have two very distinct genera descended from (I) and as these latter
+two genera, both from continued divergence of character and from
+inheritance from a different parent, will differ widely from the three
+genera descended from (A), the two little groups of genera will form two
+distinct families, or even orders, according to the amount of divergent
+modification supposed to be represented in the diagram.  And the two new
+families, or orders, will have descended from two species of the original
+genus; and these two species are supposed to have descended from one
+species of a still more ancient and unknown genus.
+</para>
+
+<para>
+We have seen that in each country it is the species of the larger genera
+which oftenest present varieties or incipient species.  This, indeed, might
+have been expected; for as natural selection acts through one form having
+some advantage over other forms in the struggle for existence, it will
+chiefly act on those which already have some advantage; and the largeness
+of any group shows that its species have inherited from a common ancestor
+some advantage in common.  Hence, the struggle for the production of new
+and modified descendants, will mainly lie between the larger groups, which
+are all trying to increase in number.  One large group will slowly conquer
+another large group, reduce its numbers, and thus lessen its chance of
+further variation and improvement.  Within the same large group, the later
+and more highly perfected sub-groups, from branching out and seizing on
+many new places in the polity of Nature, will constantly tend to supplant
+and destroy the earlier and less improved sub-groups.  Small and broken
+groups and sub-groups will finally tend to disappear.  Looking to the
+future, we can predict that the groups of organic beings which are now
+large and triumphant, and which are least broken up, that is, which as yet
+have suffered least extinction, will for a long period continue to
+increase.  But which groups will ultimately prevail, no man can predict;
+for we well know that many groups, formerly most extensively developed,
+have now become extinct.  Looking still more remotely to the future, we may
+predict that, owing to the continued and steady increase of the larger
+groups, a multitude of smaller groups will become utterly extinct, and
+leave no modified descendants; and consequently that of the species living
+at any one period, extremely few will transmit descendants to a remote
+futurity.  I shall have to return to this subject in the chapter on
+Classification, but I may add that on this view of extremely few of the
+more ancient species having transmitted descendants, and on the view of all
+the descendants of the same species making a class, we can understand how
+it is that there exist but very few classes in each main division of the
+animal and vegetable kingdoms.  Although extremely few of the most ancient
+species may now have living and modified descendants, yet at the most
+remote geological period, the earth may have been as well peopled with many
+species of many genera, families, orders, and classes, as at the present
+day.
+</para>
+
+<para>
+Summary of Chapter -- If during the long course of ages and under varying
+conditions of life, organic beings vary at all in the several parts of
+their organisation, and I think this cannot be disputed; if there be, owing
+to the high geometrical powers of increase of each species, at some age,
+season, or year, a severe struggle for life, and this certainly cannot be
+disputed; then, considering the infinite complexity of the relations of all
+organic beings to each other and to their conditions of existence, causing
+an infinite diversity in structure, constitution, and habits, to be
+advantageous to them, I think it would be a most extraordinary fact if no
+variation ever had occurred useful to each being's own welfare, in the same
+way as so many variations have occurred useful to man.  But if variations
+useful to any organic being do occur, assuredly individuals thus
+characterised will have the best chance of being preserved in the struggle
+for life; and from the strong principle of inheritance they will tend to
+produce offspring similarly characterised.  This principle of preservation,
+I have called, for the sake of brevity, Natural Selection.  Natural
+selection, on the principle of qualities being inherited at corresponding
+ages, can modify the egg, seed, or young, as easily as the adult.  Amongst
+many animals, sexual selection will give its aid to ordinary selection, by
+assuring to the most vigorous and best adapted males the greatest number of
+offspring.  Sexual selection will also give characters useful to the males
+alone, in their struggles with other males.
+</para>
+
+<para>
+Whether natural selection has really thus acted in nature, in modifying and
+adapting the various forms of life to their several conditions and
+stations, must be judged of by the general tenour and balance of evidence
+given in the following chapters.  But we already see how it entails
+extinction; and how largely extinction has acted in the world's history,
+geology plainly declares.  Natural selection, also, leads to divergence of
+character; for more living beings can be supported on the same area the
+more they diverge in structure, habits, and constitution, of which we see
+proof by looking at the inhabitants of any small spot or at naturalised
+productions.  Therefore during the modification of the descendants of any
+one species, and during the incessant struggle of all species to increase
+in numbers, the more diversified these descendants become, the better will
+be their chance of succeeding in the battle of life.  Thus the small
+differences distinguishing varieties of the same species, will steadily
+tend to increase till they come to equal the greater differences between
+species of the same genus, or even of distinct genera.
+</para>
+
+<para>
+We have seen that it is the common, the widely-diffused, and widely-ranging
+species, belonging to the larger genera, which vary most; and these will
+tend to transmit to their modified offspring that superiority which now
+makes them dominant in their own countries.  Natural selection, as has just
+been remarked, leads to divergence of character and to much extinction of
+the less improved and intermediate forms of life.  On these principles, I
+believe, the nature of the affinities of all organic beings may be
+explained.  It is a truly wonderful fact--the wonder of which we are apt to
+overlook from familiarity--that all animals and all plants throughout all
+time and space should be related to each other in group subordinate to
+group, in the manner which we everywhere behold--namely, varieties of the
+same species most closely related together, species of the same genus less
+closely and unequally related together, forming sections and sub-genera,
+species of distinct genera much less closely related, and genera related in
+different degrees, forming sub-families, families, orders, sub-classes, and
+classes.  The several subordinate groups in any class cannot be ranked in a
+single file, but seem rather to be clustered round points, and these round
+other points, and so on in almost endless cycles.  On the view that each
+species has been independently created, I can see no explanation of this
+great fact in the classification of all organic beings; but, to the best of
+my judgment, it is explained through inheritance and the complex action of
+natural selection, entailing extinction and divergence of character, as we
+have seen illustrated in the diagram.
+</para>
+
+<para>
+The affinities of all the beings of the same class have sometimes been
+represented by a great tree.  I believe this simile largely speaks the
+truth.  The green and budding twigs may represent existing species; and
+those produced during each former year may represent the long succession of
+extinct species.  At each period of growth all the growing twigs have tried
+to branch out on all sides, and to overtop and kill the surrounding twigs
+and branches, in the same manner as species and groups of species have
+tried to overmaster other species in the great battle for life.  The limbs
+divided into great branches, and these into lesser and lesser branches,
+were themselves once, when the tree was small, budding twigs; and this
+connexion of the former and present buds by ramifying branches may well
+represent the classification of all extinct and living species in groups
+subordinate to groups.  Of the many twigs which flourished when the tree
+was a mere bush, only two or three, now grown into great branches, yet
+survive and bear all the other branches; so with the species which lived
+during long-past geological periods, very few now have living and modified
+descendants.  From the first growth of the tree, many a limb and branch has
+decayed and dropped off; and these lost branches of various sizes may
+represent those whole orders, families, and genera which have now no living
+representatives, and which are known to us only from having been found in a
+fossil state.  As we here and there see a thin straggling branch springing
+from a fork low down in a tree, and which by some chance has been favoured
+and is still alive on its summit, so we occasionally see an animal like the
+Ornithorhynchus or Lepidosiren, which in some small degree connects by its
+affinities two large branches of life, and which has apparently been saved
+from fatal competition by having inhabited a protected station.  As buds
+give rise by growth to fresh buds, and these, if vigorous, branch out and
+overtop on all sides many a feebler branch, so by generation I believe it
+has been with the great Tree of Life, which fills with its dead and broken
+branches the crust of the earth, and covers the surface with its ever
+branching and beautiful ramifications.
+</para>
+
+</chapter>
+
+<chapter>
+<chapheader>
+
+<chapnum>Chapter V</chapnum>
+
+<title>Laws of Variation</title>
+
+<chapsummary>
+Effects of external conditions -- Use and disuse, combined with natural
+selection; organs of flight and of vision -- Acclimatisation -- Correlation
+of growth -- Compensation and economy of growth -- False correlations --
+Multiple, rudimentary, and lowly organised structures variable -- Parts
+developed in an unusual manner are highly variable: specific characters
+more variable than generic:  secondary sexual characters variable --
+Species of the same genus vary in an analogous manner -- Reversions to long
+lost characters -- Summary.
+</chapsummary>
+</chapheader>
+
+<para>
+I have hitherto sometimes spoken as if the variations--so common and
+multiform in organic beings under domestication, and in a lesser degree in
+those in a state of nature--had been due to chance.  This, of course, is a
+wholly incorrect expression, but it serves to acknowledge plainly our
+ignorance of the cause of each particular variation.  Some authors believe
+it to be as much the function of the reproductive system to produce
+individual differences, or very slight deviations of structure, as to make
+the child like its parents.  But the much greater variability, as well as
+the greater frequency of monstrosities, under domestication or cultivation,
+than under nature, leads me to believe that deviations of structure are in
+some way due to the nature of the conditions of life, to which the parents
+and their more remote ancestors have been exposed during several
+generations.  I have remarked in the first chapter--but a long catalogue of
+facts which cannot be here given would be necessary to show the truth of
+the remark--that the reproductive system is eminently susceptible to
+changes in the conditions of life; and to this system being functionally
+disturbed in the parents, I chiefly attribute the varying or plastic
+condition of the offspring.  The male and female sexual elements seem to be
+affected before that union takes place which is to form a new being.  In
+the case of 'sporting' plants, the bud, which in its earliest condition
+does not apparently differ essentially from an ovule, is alone affected. 
+But why, because the reproductive system is disturbed, this or that part
+should vary more or less, we are profoundly ignorant.  Nevertheless, we can
+here and there dimly catch a faint ray of light, and we may feel sure that
+there must be some cause for each deviation of structure, however slight.
+</para>
+
+<para>
+How much direct effect difference of climate, food, &amp;c., produces on any
+being is extremely doubtful.  My impression is, that the effect is
+extremely small in the case of animals, but perhaps rather more in that of
+plants.  We may, at least, safely conclude that such influences cannot have
+produced the many striking and complex co-adaptations of structure between
+one organic being and another, which we see everywhere throughout nature. 
+Some little influence may be attributed to climate, food, &amp;c.:  thus, E.
+Forbes speaks confidently that shells at their southern limit, and when
+living in shallow water, are more brightly coloured than those of the same
+species further north or from greater depths.  Gould believes that birds of
+the same species are more brightly coloured under a clear atmosphere, than
+when living on islands or near the coast.  So with insects, Wollaston is
+convinced that residence near the sea affects their colours.  Moquin-Tandon
+gives a list of plants which when growing near the sea-shore have their
+leaves in some degree fleshy, though not elsewhere fleshy.  Several other
+such cases could be given.
+</para>
+
+<para>
+The fact of varieties of one species, when they range into the zone of
+habitation of other species, often acquiring in a very slight degree some
+of the characters of such species, accords with our view that species of
+all kinds are only well-marked and permanent varieties.  Thus the species
+of shells which are confined to tropical and shallow seas are generally
+brighter-coloured than those confined to cold and deeper seas.  The birds
+which are confined to continents are, according to Mr. Gould,
+brighter-coloured than those of islands.  The insect-species confined to
+sea-coasts, as every collector knows, are often brassy or lurid.  Plants
+which live exclusively on the sea-side are very apt to have fleshy leaves. 
+He who believes in the creation of each species, will have to say that this
+shell, for instance, was created with bright colours for a warm sea; but
+that this other shell became bright-coloured by variation when it ranged
+into warmer or shallower waters.
+</para>
+
+<para>
+When a variation is of the slightest use to a being, we cannot tell how
+much of it to attribute to the accumulative action of natural selection,
+and how much to the conditions of life.  Thus, it is well known to furriers
+that animals of the same species have thicker and better fur the more
+severe the climate is under which they have lived; but who can tell how
+much of this difference may be due to the warmest-clad individuals having
+been favoured and preserved during many generations, and how much to the
+direct action of the severe climate? for it would appear that climate has
+some direct action on the hair of our domestic quadrupeds.
+</para>
+
+<para>
+Instances could be given of the same variety being produced under
+conditions of life as different as can well be conceived; and, on the other
+hand, of different varieties being produced from the same species under the
+same conditions.  Such facts show how indirectly the conditions of life
+must act.  Again, innumerable instances are known to every naturalist of
+species keeping true, or not varying at all, although living under the most
+opposite climates.  Such considerations as these incline me to lay very
+little weight on the direct action of the conditions of life.  Indirectly,
+as already remarked, they seem to play an important part in affecting the
+reproductive system, and in thus inducing variability; and natural
+selection will then accumulate all profitable variations, however slight,
+until they become plainly developed and appreciable by us.
+</para>
+
+<para>
+Effects of Use and Disuse. -- From the facts alluded to in the first
+chapter, I think there can be little doubt that use in our domestic animals
+strengthens and enlarges certain parts, and disuse diminishes them; and
+that such modifications are inherited.  Under free nature, we can have no
+standard of comparison, by which to judge of the effects of long-continued
+use or disuse, for we know not the parent-forms; but many animals have
+structures which can be explained by the effects of disuse.  As Professor
+Owen has remarked, there is no greater anomaly in nature than a bird that
+cannot fly; yet there are several in this state.  The logger-headed duck of
+South America can only flap along the surface of the water, and has its
+wings in nearly the same condition as the domestic Aylesbury duck.  As the
+larger ground-feeding birds seldom take flight except to escape danger, I
+believe that the nearly wingless condition of several birds, which now
+inhabit or have lately inhabited several oceanic islands, tenanted by no
+beast of prey, has been caused by disuse.  The ostrich indeed inhabits
+continents and is exposed to danger from which it cannot escape by flight,
+but by kicking it can defend itself from enemies, as well as any of the
+smaller quadrupeds.  We may imagine that the early progenitor of the
+ostrich had habits like those of a bustard, and that as natural selection
+increased in successive generations the size and weight of its body, its
+legs were used more, and its wings less, until they became incapable of
+flight.
+</para>
+
+<para>
+Kirby has remarked (and I have observed the same fact) that the anterior
+tarsi, or feet, of many male dung-feeding beetles are very often broken
+off; he examined seventeen specimens in his own collection, and not one had
+even a relic left.  In the Onites apelles the tarsi are so habitually lost,
+that the insect has been described as not having them.  In some other
+genera they are present, but in a rudimentary condition.  In the Ateuchus
+or sacred beetle of the Egyptians, they are totally deficient.  There is
+not sufficient evidence to induce us to believe that mutilations are ever
+inherited; and I should prefer explaining the entire absence of the
+anterior tarsi in Ateuchus, and their rudimentary condition in some other
+genera, by the long-continued effects of disuse in their progenitors; for
+as the tarsi are almost always lost in many dung-feeding beetles, they must
+be lost early in life, and therefore cannot be much used by these insects.
+</para>
+
+<para>
+In some cases we might easily put down to disuse modifications of structure
+which are wholly, or mainly, due to natural selection.  Mr. Wollaston has
+discovered the remarkable fact that 200 beetles, out of the 550 species
+inhabiting Madeira, are so far deficient in wings that they cannot fly; and
+that of the twenty-nine endemic genera, no less than twenty-three genera
+have all their species in this condition!  Several facts, namely, that
+beetles in many parts of the world are very frequently blown to sea and
+perish; that the beetles in Madeira, as observed by Mr. Wollaston, lie much
+concealed, until the wind lulls and the sun shines; that the proportion of
+wingless beetles is larger on the exposed Dezertas than in Madeira itself;
+and especially the extraordinary fact, so strongly insisted on by Mr.
+Wollaston, of the almost entire absence of certain large groups of beetles,
+elsewhere excessively numerous, and which groups have habits of life almost
+necessitating frequent flight;--these several considerations have made me
+believe that the wingless condition of so many Madeira beetles is mainly
+due to the action of natural selection, but combined probably with disuse. 
+For during thousands of successive generations each individual beetle which
+flew least, either from its wings having been ever so little less perfectly
+developed or from indolent habit, will have had the best chance of
+surviving from not being blown out to sea; and, on the other hand, those
+beetles which most readily took to flight will oftenest have been blown to
+sea and thus have been destroyed.
+</para>
+
+<para>
+The insects in Madeira which are not ground-feeders, and which, as the
+flower-feeding coleoptera and lepidoptera, must habitually use their wings
+to gain their subsistence, have, as Mr. Wollaston suspects, their wings not
+at all reduced, but even enlarged.  This is quite compatible with the
+action of natural selection.  For when a new insect first arrived on the
+island, the tendency of natural selection to enlarge or to reduce the
+wings, would depend on whether a greater number of individuals were saved
+by successfully battling with the winds, or by giving up the attempt and
+rarely or never flying.  As with mariners shipwrecked near a coast, it
+would have been better for the good swimmers if they had been able to swim
+still further, whereas it would have been better for the bad swimmers if
+they had not been able to swim at all and had stuck to the wreck.
+</para>
+
+<para>
+The eyes of moles and of some burrowing rodents are rudimentary in size,
+and in some cases are quite covered up by skin and fur.  This state of the
+eyes is probably due to gradual reduction from disuse, but aided perhaps by
+natural selection.  In South America, a burrowing rodent, the tuco-tuco, or
+Ctenomys, is even more subterranean in its habits than the mole; and I was
+assured by a Spaniard, who had often caught them, that they were frequently
+blind; one which I kept alive was certainly in this condition, the cause,
+as appeared on dissection, having been inflammation of the nictitating
+membrane.  As frequent inflammation of the eyes must be injurious to any
+animal, and as eyes are certainly not indispensable to animals with
+subterranean habits, a reduction in their size with the adhesion of the
+eyelids and growth of fur over them, might in such case be an advantage;
+and if so, natural selection would constantly aid the effects of disuse.
+</para>
+
+<para>
+It is well known that several animals, belonging to the most different
+classes, which inhabit the caves of Styria and of Kentucky, are blind.  In
+some of the crabs the foot-stalk for the eye remains, though the eye is
+gone; the stand for the telescope is there, though the telescope with its
+glasses has been lost.  As it is difficult to imagine that eyes, though
+useless, could be in any way injurious to animals living in darkness, I
+attribute their loss wholly to disuse.  In one of the blind animals,
+namely, the cave-rat, the eyes are of immense size; and Professor Silliman
+thought that it regained, after living some days in the light, some slight
+power of vision.  In the same manner as in Madeira the wings of some of the
+insects have been enlarged, and the wings of others have been reduced by
+natural selection aided by use and disuse, so in the case of the cave-rat
+natural selection seems to have struggled with the loss of light and to
+have increased the size of the eyes; whereas with all the other inhabitants
+of the caves, disuse by itself seems to have done its work.
+</para>
+
+<para>
+It is difficult to imagine conditions of life more similar than deep
+limestone caverns under a nearly similar climate; so that on the common
+view of the blind animals having been separately created for the American
+and European caverns, close similarity in their organisation and affinities
+might have been expected; but, as Schiodte and others have remarked, this
+is not the case, and the cave-insects of the two continents are not more
+closely allied than might have been anticipated from the general
+resemblance of the other inhabitants of North America and Europe.  On my
+view we must suppose that American animals, having ordinary powers of
+vision, slowly migrated by successive generations from the outer world into
+the deeper and deeper recesses of the Kentucky caves, as did European
+animals into the caves of Europe.  We have some evidence of this gradation
+of habit; for, as Schiodte remarks, 'animals not far remote from ordinary
+forms, prepare the transition from light to darkness.  Next follow those
+that are constructed for twilight; and, last of all, those destined for
+total darkness.'  By the time that an animal had reached, after numberless
+generations, the deepest recesses, disuse will on this view have more or
+less perfectly obliterated its eyes, and natural selection will often have
+effected other changes, such as an increase in the length of the antennae
+or palpi, as a compensation for blindness.  Notwithstanding such
+modifications, we might expect still to see in the cave-animals of America,
+affinities to the other inhabitants of that continent, and in those of
+Europe, to the inhabitants of the European continent.  And this is the case
+with some of the American cave-animals, as I hear from Professor Dana; and
+some of the European cave-insects are very closely allied to those of the
+surrounding country.  It would be most difficult to give any rational
+explanation of the affinities of the blind cave-animals to the other
+inhabitants of the two continents on the ordinary view of their independent
+creation.  That several of the inhabitants of the caves of the Old and New
+Worlds should be closely related, we might expect from the well-known
+relationship of most of their other productions.  Far from feeling any
+surprise that some of the cave-animals should be very anomalous, as Agassiz
+has remarked in regard to the blind fish, the Amblyopsis, and as is the
+case with the blind Proteus with reference to the reptiles of Europe, I am
+only surprised that more wrecks of ancient life have not been preserved,
+owing to the less severe competition to which the inhabitants of these dark
+abodes will probably have been exposed.
+</para>
+
+<para>
+Acclimatisation. -- Habit is hereditary with plants, as in the period of
+flowering, in the amount of rain requisite for seeds to germinate, in the
+time of sleep, &amp;c., and this leads me to say a few words on
+acclimatisation.  As it is extremely common for species of the same genus
+to inhabit very hot and very cold countries, and as I believe that all the
+species of the same genus have descended from a single parent, if this view
+be correct, acclimatisation must be readily effected during long-continued
+descent.  It is notorious that each species is adapted to the climate of
+its own home:  species from an arctic or even from a temperate region
+cannot endure a tropical climate, or conversely.  So again, many succulent
+plants cannot endure a damp climate.  But the degree of adaptation of
+species to the climates under which they live is often overrated.  We may
+infer this from our frequent inability to predict whether or not an
+imported plant will endure our climate, and from the number of plants and
+animals brought from warmer countries which here enjoy good health.  We
+have reason to believe that species in a state of nature are limited in
+their ranges by the competition of other organic beings quite as much as,
+or more than, by adaptation to particular climates.  But whether or not the
+adaptation be generally very close, we have evidence, in the case of some
+few plants, of their becoming, to a certain extent, naturally habituated to
+different temperatures, or becoming acclimatised:  thus the pines and
+rhododendrons, raised from seed collected by Dr. Hooker from trees growing
+at different heights on the Himalaya, were found in this country to possess
+different constitutional powers of resisting cold.  Mr. Thwaites informs me
+that he has observed similar facts in Ceylon, and analogous observations
+have been made by Mr. H. C. Watson on European species of plants brought
+from the Azores to England.  In regard to animals, several authentic cases
+could be given of species within historical times having largely extended
+their range from warmer to cooler latitudes, and conversely; but we do not
+positively know that these animals were strictly adapted to their native
+climate, but in all ordinary cases we assume such to be the case; nor do we
+know that they have subsequently become acclimatised to their new homes.
+</para>
+
+<para>
+As I believe that our domestic animals were originally chosen by
+uncivilised man because they were useful and bred readily under
+confinement, and not because they were subsequently found capable of
+far-extended transportation, I think the common and extraordinary capacity
+in our domestic animals of not only withstanding the most different
+climates but of being perfectly fertile (a far severer test) under them,
+may be used as an argument that a large proportion of other animals, now in
+a state of nature, could easily be brought to bear widely different
+climates.  We must not, however, push the foregoing argument too far, on
+account of the probable origin of some of our domestic animals from several
+wild stocks:  the blood, for instance, of a tropical and arctic wolf or
+wild dog may perhaps be mingled in our domestic breeds.  The rat and mouse
+cannot be considered as domestic animals, but they have been transported by
+man to many parts of the world, and now have a far wider range than any
+other rodent, living free under the cold climate of Faroe in the north and
+of the Falklands in the south, and on many islands in the torrid zones. 
+Hence I am inclined to look at adaptation to any special climate as a
+quality readily grafted on an innate wide flexibility of constitution,
+which is common to most animals.  On this view, the capacity of enduring
+the most different climates by man himself and by his domestic animals, and
+such facts as that former species of the elephant and rhinoceros were
+capable of enduring a glacial climate, whereas the living species are now
+all tropical or sub-tropical in their habits, ought not to be looked at as
+anomalies, but merely as examples of a very common flexibility of
+constitution, brought, under peculiar circumstances, into play.
+</para>
+
+<para>
+How much of the acclimatisation of species to any peculiar climate is due
+to mere habit, and how much to the natural selection of varieties having
+different innate constitutions, and how much to both means combined, is a
+very obscure question.  That habit or custom has some influence I must
+believe, both from analogy, and from the incessant advice given in
+agricultural works, even in the ancient Encyclopaedias of China, to be very
+cautious in transposing animals from one district to another; for it is not
+likely that man should have succeeded in selecting so many breeds and
+sub-breeds with constitutions specially fitted for their own districts: 
+the result must, I think, be due to habit.  On the other hand, I can see no
+reason to doubt that natural selection will continually tend to preserve
+those individuals which are born with constitutions best adapted to their
+native countries.  In treatises on many kinds of cultivated plants, certain
+varieties are said to withstand certain climates better than others:  this
+is very strikingly shown in works on fruit trees published in the United
+States, in which certain varieties are habitually recommended for the
+northern, and others for the southern States; and as most of these
+varieties are of recent origin, they cannot owe their constitutional
+differences to habit.  The case of the Jerusalem artichoke, which is never
+propagated by seed, and of which consequently new varieties have not been
+produced, has even been advanced--for it is now as tender as ever it
+was--as proving that acclimatisation cannot be effected!  The case, also,
+of the kidney-bean has been often cited for a similar purpose, and with
+much greater weight; but until some one will sow, during a score of
+generations, his kidney-beans so early that a very large proportion are
+destroyed by frost, and then collect seed from the few survivors, with care
+to prevent accidental crosses, and then again get seed from these
+seedlings, with the same precautions, the experiment cannot be said to have
+been even tried.  Nor let it be supposed that no differences in the
+constitution of seedling kidney-beans ever appear, for an account has been
+published how much more hardy some seedlings appeared to be than others.
+</para>
+
+<para>
+On the whole, I think we may conclude that habit, use, and disuse, have, in
+some cases, played a considerable part in the modification of the
+constitution, and of the structure of various organs; but that the effects
+of use and disuse have often been largely combined with, and sometimes
+overmastered by, the natural selection of innate differences.
+</para>
+
+<para>
+Correlation of Growth. -- I mean by this expression that the whole
+organisation is so tied together during its growth and development, that
+when slight variations in any one part occur, and are accumulated through
+natural selection, other parts become modified.  This is a very important
+subject, most imperfectly understood.  The most obvious case is, that
+modifications accumulated solely for the good of the young or larva, will,
+it may safely be concluded, affect the structure of the adult; in the same
+manner as any malconformation affecting the early embryo, seriously affects
+the whole organisation of the adult.  The several parts of the body which
+are homologous, and which, at an early embryonic period, are alike, seem
+liable to vary in an allied manner:  we see this in the right and left
+sides of the body varying in the same manner; in the front and hind legs,
+and even in the jaws and limbs, varying together, for the lower jaw is
+believed to be homologous with the limbs.  These tendencies, I do not
+doubt, may be mastered more or less completely by natural selection:  thus
+a family of stags once existed with an antler only on one side; and if this
+had been of any great use to the breed it might probably have been rendered
+permanent by natural selection.
+</para>
+
+<para>
+Homologous parts, as has been remarked by some authors, tend to cohere;
+this is often seen in monstrous plants; and nothing is more common than the
+union of homologous parts in normal structures, as the union of the petals
+of the corolla into a tube.  Hard parts seem to affect the form of
+adjoining soft parts; it is believed by some authors that the diversity in
+the shape of the pelvis in birds causes the remarkable diversity in the
+shape of their kidneys.  Others believe that the shape of the pelvis in the
+human mother influences by pressure the shape of the head of the child.  In
+snakes, according to Schlegel, the shape of the body and the manner of
+swallowing determine the position of several of the most important viscera.
+</para>
+
+<para>
+The nature of the bond of correlation is very frequently quite obscure.  M.
+Is. Geoffroy St. Hilaire has forcibly remarked, that certain
+malconformations very frequently, and that others rarely coexist, without
+our being able to assign any reason.  What can be more singular than the
+relation between blue eyes and deafness in cats, and the tortoise-shell
+colour with the female sex; the feathered feet and skin between the outer
+toes in pigeons, and the presence of more or less down on the young birds
+when first hatched, with the future colour of their plumage; or, again, the
+relation between the hair and teeth in the naked Turkish dog, though here
+probably homology comes into play?  With respect to this latter case of
+correlation, I think it can hardly be accidental, that if we pick out the
+two orders of mammalia which are most abnormal in their dermal coverings,
+viz. Cetacea (whales) and Edentata (armadilloes, scaly ant-eaters, &amp;c.),
+that these are likewise the most abnormal in their teeth.
+</para>
+
+<para>
+I know of no case better adapted to show the importance of the laws of
+correlation in modifying important structures, independently of utility
+and, therefore, of natural selection, than that of the difference between
+the outer and inner flowers in some Compositous and Umbelliferous plants. 
+Every one knows the difference in the ray and central florets of, for
+instance, the daisy, and this difference is often accompanied with the
+abortion of parts of the flower.  But, in some Compositous plants, the
+seeds also differ in shape and sculpture; and even the ovary itself, with
+its accessory parts, differs, as has been described by Cassini.  These
+differences have been attributed by some authors to pressure, and the shape
+of the seeds in the ray-florets in some Compositae countenances this idea;
+but, in the case of the corolla of the Umbelliferae, it is by no means, as
+Dr. Hooker informs me, in species with the densest heads that the inner and
+outer flowers most frequently differ.  It might have been thought that the
+development of the ray-petals by drawing nourishment from certain other
+parts of the flower had caused their abortion; but in some Compositae there
+is a difference in the seeds of the outer and inner florets without any
+difference in the corolla.  Possibly, these several differences may be
+connected with some difference in the flow of nutriment towards the central
+and external flowers:  we know, at least, that in irregular flowers, those
+nearest to the axis are oftenest subject to peloria, and become regular.  I
+may add, as an instance of this, and of a striking case of correlation,
+that I have recently observed in some garden pelargoniums, that the central
+flower of the truss often loses the patches of darker colour in the two
+upper petals; and that when this occurs, the adherent nectary is quite
+aborted; when the colour is absent from only one of the two upper petals,
+the nectary is only much shortened.
+</para>
+
+<para>
+With respect to the difference in the corolla of the central and exterior
+flowers of a head or umbel, I do not feel at all sure that C. C. Sprengel's
+idea that the ray-florets serve to attract insects, whose agency is highly
+advantageous in the fertilisation of plants of these two orders, is so
+far-fetched, as it may at first appear:  and if it be advantageous, natural
+selection may have come into play.  But in regard to the differences both
+in the internal and external structure of the seeds, which are not always
+correlated with any differences in the flowers, it seems impossible that
+they can be in any way advantageous to the plant:  yet in the Umbelliferae
+these differences are of such apparent importance--the seeds being in some
+cases, according to Tausch, orthospermous in the exterior flowers and
+coelospermous in the central flowers,--that the elder De Candolle founded
+his main divisions of the order on analogous differences.  Hence we see
+that modifications of structure, viewed by systematists as of high value,
+may be wholly due to unknown laws of correlated growth, and without being,
+as far as we can see, of the slightest service to the species.
+</para>
+
+<para>
+We may often falsely attribute to correlation of growth, structures which
+are common to whole groups of species, and which in truth are simply due to
+inheritance; for an ancient progenitor may have acquired through natural
+selection some one modification in structure, and, after thousands of
+generations, some other and independent modification; and these two
+modifications, having been transmitted to a whole group of descendants with
+diverse habits, would naturally be thought to be correlated in some
+necessary manner.  So, again, I do not doubt that some apparent
+correlations, occurring throughout whole orders, are entirely due to the
+manner alone in which natural selection can act.  For instance, Alph. De
+Candolle has remarked that winged seeds are never found in fruits which do
+not open:  I should explain the rule by the fact that seeds could not
+gradually become winged through natural selection, except in fruits which
+opened; so that the individual plants producing seeds which were a little
+better fitted to be wafted further, might get an advantage over those
+producing seed less fitted for dispersal; and this process could not
+possibly go on in fruit which did not open.
+</para>
+
+<para>
+The elder Geoffroy and Goethe propounded, at about the same period, their
+law of compensation or balancement of growth; or, as Goethe expressed it,
+'in order to spend on one side, nature is forced to economise on the other
+side.'  I think this holds true to a certain extent with our domestic
+productions:  if nourishment flows to one part or organ in excess, it
+rarely flows, at least in excess, to another part; thus it is difficult to
+get a cow to give much milk and to fatten readily.  The same varieties of
+the cabbage do not yield abundant and nutritious foliage and a copious
+supply of oil-bearing seeds.  When the seeds in our fruits become
+atrophied, the fruit itself gains largely in size and quality.  In our
+poultry, a large tuft of feathers on the head is generally accompanied by a
+diminished comb, and a large beard by diminished wattles.  With species in
+a state of nature it can hardly be maintained that the law is of universal
+application; but many good observers, more especially botanists, believe in
+its truth.  I will not, however, here give any instances, for I see hardly
+any way of distinguishing between the effects, on the one hand, of a part
+being largely developed through natural selection and another and adjoining
+part being reduced by this same process or by disuse, and, on the other
+hand, the actual withdrawal of nutriment from one part owing to the excess
+of growth in another and adjoining part.
+</para>
+
+<para>
+I suspect, also, that some of the cases of compensation which have been
+advanced, and likewise some other facts, may be merged under a more general
+principle, namely, that natural selection is continually trying to
+economise in every part of the organisation.  If under changed conditions
+of life a structure before useful becomes less useful, any diminution,
+however slight, in its development, will be seized on by natural selection,
+for it will profit the individual not to have its nutriment wasted in
+building up an useless structure.  I can thus only understand a fact with
+which I was much struck when examining cirripedes, and of which many other
+instances could be given:  namely, that when a cirripede is parasitic
+within another and is thus protected, it loses more or less completely its
+own shell or carapace.  This is the case with the male Ibla, and in a truly
+extraordinary manner with the Proteolepas:  for the carapace in all other
+cirripedes consists of the three highly-important anterior segments of the
+head enormously developed, and furnished with great nerves and muscles; but
+in the parasitic and protected Proteolepas, the whole anterior part of the
+head is reduced to the merest rudiment attached to the bases of the
+prehensile antennae.  Now the saving of a large and complex structure, when
+rendered superfluous by the parasitic habits of the Proteolepas, though
+effected by slow steps, would be a decided advantage to each successive
+individual of the species; for in the struggle for life to which every
+animal is exposed, each individual Proteolepas would have a better chance
+of supporting itself, by less nutriment being wasted in developing a
+structure now become useless.
+</para>
+
+<para>
+Thus, as I believe, natural selection will always succeed in the long run
+in reducing and saving every part of the organisation, as soon as it is
+rendered superfluous, without by any means causing some other part to be
+largely developed in a corresponding degree.  And, conversely, that natural
+selection may perfectly well succeed in largely developing any organ,
+without requiring as a necessary compensation the reduction of some
+adjoining part.
+</para>
+
+<para>
+It seems to be a rule, as remarked by Is. Geoffroy St. Hilaire, both in
+varieties and in species, that when any part or organ is repeated many
+times in the structure of the same individual (as the vertebrae in snakes,
+and the stamens in polyandrous flowers) the number is variable; whereas the
+number of the same part or organ, when it occurs in lesser numbers, is
+constant.  The same author and some botanists have further remarked that
+multiple parts are also very liable to variation in structure.  Inasmuch as
+this 'vegetative repetition,' to use Prof. Owen's expression, seems to be a
+sign of low organisation; the foregoing remark seems connected with the
+very general opinion of naturalists, that beings low in the scale of nature
+are more variable than those which are higher.  I presume that lowness in
+this case means that the several parts of the organisation have been but
+little specialised for particular functions; and as long as the same part
+has to perform diversified work, we can perhaps see why it should remain
+variable, that is, why natural selection should have preserved or rejected
+each little deviation of form less carefully than when the part has to
+serve for one special purpose alone.  In the same way that a knife which
+has to cut all sorts of things may be of almost any shape; whilst a tool
+for some particular object had better be of some particular shape.  Natural
+selection, it should never be forgotten, can act on each part of each
+being, solely through and for its advantage.
+</para>
+
+<para>
+Rudimentary parts, it has been stated by some authors, and I believe with
+truth, are apt to be highly variable.  We shall have to recur to the
+general subject of rudimentary and aborted organs; and I will here only add
+that their variability seems to be owing to their uselessness, and
+therefore to natural selection having no power to check deviations in their
+structure.  Thus rudimentary parts are left to the free play of the various
+laws of growth, to the effects of long-continued disuse, and to the
+tendency to reversion.
+</para>
+
+<para>
+A part developed in any species in an extraordinary degree or manner, in
+comparison with the same part in allied species, tends to be highly
+variable. -- Several years ago I was much struck with a remark, nearly to
+the above effect, published by Mr. Waterhouse.  I infer also from an
+observation made by Professor Owen, with respect to the length of the arms
+of the ourang-outang, that he has come to a nearly similar conclusion.  It
+is hopeless to attempt to convince any one of the truth of this proposition
+without giving the long array of facts which I have collected, and which
+cannot possibly be here introduced.  I can only state my conviction that it
+is a rule of high generality.  I am aware of several causes of error, but I
+hope that I have made due allowance for them.  It should be understood that
+the rule by no means applies to any part, however unusually developed,
+unless it be unusually developed in comparison with the same part in
+closely allied species.  Thus, the bat's wing is a most abnormal structure
+in the class mammalia; but the rule would not here apply, because there is
+a whole group of bats having wings; it would apply only if some one species
+of bat had its wings developed in some remarkable manner in comparison with
+the other species of the same genus.  The rule applies very strongly in the
+case of secondary sexual characters, when displayed in any unusual manner. 
+The term, secondary sexual characters, used by Hunter, applies to
+characters which are attached to one sex, but are not directly connected
+with the act of reproduction.  The rule applies to males and females; but
+as females more rarely offer remarkable secondary sexual characters, it
+applies more rarely to them.  The rule being so plainly applicable in the
+case of secondary sexual characters, may be due to the great variability of
+these characters, whether or not displayed in any unusual manner--of which
+fact I think there can be little doubt.  But that our rule is not confined
+to secondary sexual characters is clearly shown in the case of
+hermaphrodite cirripedes; and I may here add, that I particularly attended
+to Mr. Waterhouse's remark, whilst investigating this Order, and I am fully
+convinced that the rule almost invariably holds good with cirripedes.  I
+shall, in my future work, give a list of the more remarkable cases; I will
+here only briefly give one, as it illustrates the rule in its largest
+application.  The opercular valves of sessile cirripedes (rock barnacles)
+are, in every sense of the word, very important structures, and they differ
+extremely little even in different genera; but in the several species of
+one genus, Pyrgoma, these valves present a marvellous amount of
+diversification:  the homologous valves in the different species being
+sometimes wholly unlike in shape; and the amount of variation in the
+individuals of several of the species is so great, that it is no
+exaggeration to state that the varieties differ more from each other in the
+characters of these important valves than do other species of distinct
+genera.
+</para>
+
+<para>
+As birds within the same country vary in a remarkably small degree, I have
+particularly attended to them, and the rule seems to me certainly to hold
+good in this class.  I cannot make out that it applies to plants, and this
+would seriously have shaken my belief in its truth, had not the great
+variability in plants made it particularly difficult to compare their
+relative degrees of variability.
+</para>
+
+<para>
+When we see any part or organ developed in a remarkable degree or manner in
+any species, the fair presumption is that it is of high importance to that
+species; nevertheless the part in this case is eminently liable to
+variation.  Why should this be so?  On the view that each species has been
+independently created, with all its parts as we now see them, I can see no
+explanation.  But on the view that groups of species have descended from
+other species, and have been modified through natural selection, I think we
+can obtain some light.  In our domestic animals, if any part, or the whole
+animal, be neglected and no selection be applied, that part (for instance,
+the comb in the Dorking fowl) or the whole breed will cease to have a
+nearly uniform character.  The breed will then be said to have degenerated. 
+In rudimentary organs, and in those which have been but little specialised
+for any particular purpose, and perhaps in polymorphic groups, we see a
+nearly parallel natural case; for in such cases natural selection either
+has not or cannot come into full play, and thus the organisation is left in
+a fluctuating condition.  But what here more especially concerns us is,
+that in our domestic animals those points, which at the present time are
+undergoing rapid change by continued selection, are also eminently liable
+to variation.  Look at the breeds of the pigeon; see what a prodigious
+amount of difference there is in the beak of the different tumblers, in the
+beak and wattle of the different carriers, in the carriage and tail of our
+fantails, &amp;c., these being the points now mainly attended to by English
+fanciers.  Even in the sub-breeds, as in the short-faced tumbler, it is
+notoriously difficult to breed them nearly to perfection, and frequently
+individuals are born which depart widely from the standard.  There may be
+truly said to be a constant struggle going on between, on the one hand, the
+tendency to reversion to a less modified state, as well as an innate
+tendency to further variability of all kinds, and, on the other hand, the
+power of steady selection to keep the breed true.  In the long run
+selection gains the day, and we do not expect to fail so far as to breed a
+bird as coarse as a common tumbler from a good short-faced strain.  But as
+long as selection is rapidly going on, there may always be expected to be
+much variability in the structure undergoing modification.  It further
+deserves notice that these variable characters, produced by man's
+selection, sometimes become attached, from causes quite unknown to us, more
+to one sex than to the other, generally to the male sex, as with the wattle
+of carriers and the enlarged crop of pouters.
+</para>
+
+<para>
+Now let us turn to nature.  When a part has been developed in an
+extraordinary manner in any one species, compared with the other species of
+the same genus, we may conclude that this part has undergone an
+extraordinary amount of modification, since the period when the species
+branched off from the common progenitor of the genus.  This period will
+seldom be remote in any extreme degree, as species very rarely endure for
+more than one geological period.  An extraordinary amount of modification
+implies an unusually large and long-continued amount of variability, which
+has continually been accumulated by natural selection for the benefit of
+the species.  But as the variability of the extraordinarily-developed part
+or organ has been so great and long-continued within a period not
+excessively remote, we might, as a general rule, expect still to find more
+variability in such parts than in other parts of the organisation, which
+have remained for a much longer period nearly constant.  And this, I am
+convinced, is the case.  That the struggle between natural selection on the
+one hand, and the tendency to reversion and variability on the other hand,
+will in the course of time cease; and that the most abnormally developed
+organs may be made constant, I can see no reason to doubt.  Hence when an
+organ, however abnormal it may be, has been transmitted in approximately
+the same condition to many modified descendants, as in the case of the wing
+of the bat, it must have existed, according to my theory, for an immense
+period in nearly the same state; and thus it comes to be no more variable
+than any other structure.  It is only in those cases in which the
+modification has been comparatively recent and extraordinarily great that
+we ought to find the generative variability, as it may be called, still
+present in a high degree.  For in this case the variability will seldom as
+yet have been fixed by the continued selection of the individuals varying
+in the required manner and degree, and by the continued rejection of those
+tending to revert to a former and less modified condition.
+</para>
+
+<para>
+The principle included in these remarks may be extended.  It is notorious
+that specific characters are more variable than generic.  To explain by a
+simple example what is meant.  If some species in a large genus of plants
+had blue flowers and some had red, the colour would be only a specific
+character, and no one would be surprised at one of the blue species varying
+into red, or conversely; but if all the species had blue flowers, the
+colour would become a generic character, and its variation would be a more
+unusual circumstance.  I have chosen this example because an explanation is
+not in this case applicable, which most naturalists would advance, namely,
+that specific characters are more variable than generic, because they are
+taken from parts of less physiological importance than those commonly used
+for classing genera.  I believe this explanation is partly, yet only
+indirectly, true; I shall, however, have to return to this subject in our
+chapter on Classification.  It would be almost superfluous to adduce
+evidence in support of the above statement, that specific characters are
+more variable than generic; but I have repeatedly noticed in works on
+natural history, that when an author has remarked with surprise that some
+important organ or part, which is generally very constant throughout large
+groups of species, has differed considerably in closely-allied species,
+that it has, also, been variable in the individuals of some of the species. 
+And this fact shows that a character, which is generally of generic value,
+when it sinks in value and becomes only of specific value, often becomes
+variable, though its physiological importance may remain the same. 
+Something of the same kind applies to monstrosities:  at least Is. Geoffroy
+St. Hilaire seems to entertain no doubt, that the more an organ normally
+differs in the different species of the same group, the more subject it is
+to individual anomalies.
+</para>
+
+<para>
+On the ordinary view of each species having been independently created, why
+should that part of the structure, which differs from the same part in
+other independently-created species of the same genus, be more variable
+than those parts which are closely alike in the several species?  I do not
+see that any explanation can be given.  But on the view of species being
+only strongly marked and fixed varieties, we might surely expect to find
+them still often continuing to vary in those parts of their structure which
+have varied within a moderately recent period, and which have thus come to
+differ.  Or to state the case in another manner:--the points in which all
+the species of a genus resemble each other, and in which they differ from
+the species of some other genus, are called generic characters; and these
+characters in common I attribute to inheritance from a common progenitor,
+for it can rarely have happened that natural selection will have modified
+several species, fitted to more or less widely-different habits, in exactly
+the same manner:  and as these so-called generic characters have been
+inherited from a remote period, since that period when the species first
+branched off from their common progenitor, and subsequently have not varied
+or come to differ in any degree, or only in a slight degree, it is not
+probable that they should vary at the present day.  On the other hand, the
+points in which species differ from other species of the same genus, are
+called specific characters; and as these specific characters have varied
+and come to differ within the period of the branching off of the species
+from a common progenitor, it is probable that they should still often be in
+some degree variable,--at least more variable than those parts of the
+organisation which have for a very long period remained constant.
+</para>
+
+<para>
+In connexion with the present subject, I will make only two other remarks. 
+I think it will be admitted, without my entering on details, that secondary
+sexual characters are very variable; I think it also will be admitted that
+species of the same group differ from each other more widely in their
+secondary sexual characters, than in other parts of their organisation;
+compare, for instance, the amount of difference between the males of
+gallinaceous birds, in which secondary sexual characters are strongly
+displayed, with the amount of difference between their females; and the
+truth of this proposition will be granted.  The cause of the original
+variability of secondary sexual characters is not manifest; but we can see
+why these characters should not have been rendered as constant and uniform
+as other parts of the organisation; for secondary sexual characters have
+been accumulated by sexual selection, which is less rigid in its action
+than ordinary selection, as it does not entail death, but only gives fewer
+offspring to the less favoured males.  Whatever the cause may be of the
+variability of secondary sexual characters, as they are highly variable,
+sexual selection will have had a wide scope for action, and may thus
+readily have succeeded in giving to the species of the same group a greater
+amount of difference in their sexual characters, than in other parts of
+their structure.
+</para>
+
+<para>
+It is a remarkable fact, that the secondary sexual differences between the
+two sexes of the same species are generally displayed in the very same
+parts of the organisation in which the different species of the same genus
+differ from each other.  Of this fact I will give in illustration two
+instances, the first which happen to stand on my list; and as the
+differences in these cases are of a very unusual nature, the relation can
+hardly be accidental.  The same number of joints in the tarsi is a
+character generally common to very large groups of beetles, but in the
+Engidae, as Westwood has remarked, the number varies greatly; and the
+number likewise differs in the two sexes of the same species:  again in
+fossorial hymenoptera, the manner of neuration of the wings is a character
+of the highest importance, because common to large groups; but in certain
+genera the neuration differs in the different species, and likewise in the
+two sexes of the same species.  This relation has a clear meaning on my
+view of the subject:  I look at all the species of the same genus as having
+as certainly descended from the same progenitor, as have the two sexes of
+any one of the species.  Consequently, whatever part of the structure of
+the common progenitor, or of its early descendants, became variable;
+variations of this part would it is highly probable, be taken advantage of
+by natural and sexual selection, in order to fit the several species to
+their several places in the economy of nature, and likewise to fit the two
+sexes of the same species to each other, or to fit the males and females to
+different habits of life, or the males to struggle with other males for the
+possession of the females.
+</para>
+
+<para>
+Finally, then, I conclude that the greater variability of specific
+characters, or those which distinguish species from species, than of
+generic characters, or those which the species possess in common;--that the
+frequent extreme variability of any part which is developed in a species in
+an extraordinary manner in comparison with the same part in its congeners;
+and the not great degree of variability in a part, however extraordinarily
+it may be developed, if it be common to a whole group of species;--that the
+great variability of secondary sexual characters, and the great amount of
+difference in these same characters between closely allied species;--that
+secondary sexual and ordinary specific differences are generally displayed
+in the same parts of the organisation,--are all principles closely
+connected together.  All being mainly due to the species of the same group
+having descended from a common progenitor, from whom they have inherited
+much in common,--to parts which have recently and largely varied being more
+likely still to go on varying than parts which have long been inherited and
+have not varied,--to natural selection having more or less completely,
+according to the lapse of time, overmastered the tendency to reversion and
+to further variability,--to sexual selection being less rigid than ordinary
+selection,--and to variations in the same parts having been accumulated by
+natural and sexual selection, and thus adapted for secondary sexual, and
+for ordinary specific purposes.
+</para>
+
+<para>
+Distinct species present analogous variations; and a variety of one species
+often assumes some of the characters of an allied species, or reverts to
+some of the characters of an early progenitor. -- These propositions will
+be most readily understood by looking to our domestic races.  The most
+distinct breeds of pigeons, in countries most widely apart, present
+sub-varieties with reversed feathers on the head and feathers on the
+feet,--characters not possessed by the aboriginal rock-pigeon; these then
+are analogous variations in two or more distinct races.  The frequent
+presence of fourteen or even sixteen tail-feathers in the pouter, may be
+considered as a variation representing the normal structure of another
+race, the fantail.  I presume that no one will doubt that all such
+analogous variations are due to the several races of the pigeon having
+inherited from a common parent the same constitution and tendency to
+variation, when acted on by similar unknown influences.  In the vegetable
+kingdom we have a case of analogous variation, in the enlarged stems, or
+roots as commonly called, of the Swedish turnip and Ruta baga, plants which
+several botanists rank as varieties produced by cultivation from a common
+parent:  if this be not so, the case will then be one of analogous
+variation in two so-called distinct species; and to these a third may be
+added, namely, the common turnip.  According to the ordinary view of each
+species having been independently created, we should have to attribute this
+similarity in the enlarged stems of these three plants, not to the vera
+causa of community of descent, and a consequent tendency to vary in a like
+manner, but to three separate yet closely related acts of creation.
+</para>
+
+<para>
+With pigeons, however, we have another case, namely, the occasional
+appearance in all the breeds, of slaty-blue birds with two black bars on
+the wings, a white rump, a bar at the end of the tail, with the outer
+feathers externally edged near their bases with white.  As all these marks
+are characteristic of the parent rock-pigeon, I presume that no one will
+doubt that this is a case of reversion, and not of a new yet analogous
+variation appearing in the several breeds.  We may I think confidently come
+to this conclusion, because, as we have seen, these coloured marks are
+eminently liable to appear in the crossed offspring of two distinct and
+differently coloured breeds; and in this case there is nothing in the
+external conditions of life to cause the reappearance of the slaty-blue,
+with the several marks, beyond the influence of the mere act of crossing on
+the laws of inheritance.
+</para>
+
+<para>
+No doubt it is a very surprising fact that characters should reappear after
+having been lost for many, perhaps for hundreds of generations.  But when a
+breed has been crossed only once by some other breed, the offspring
+occasionally show a tendency to revert in character to the foreign breed
+for many generations--some say, for a dozen or even a score of generations. 
+After twelve generations, the proportion of blood, to use a common
+expression, of any one ancestor, is only 1 in 2048; and yet, as we see, it
+is generally believed that a tendency to reversion is retained by this very
+small proportion of foreign blood.  In a breed which has not been crossed,
+but in which both parents have lost some character which their progenitor
+possessed, the tendency, whether strong or weak, to reproduce the lost
+character might be, as was formerly remarked, for all that we can see to
+the contrary, transmitted for almost any number of generations.  When a
+character which has been lost in a breed, reappears after a great number of
+generations, the most probable hypothesis is, not that the offspring
+suddenly takes after an ancestor some hundred generations distant, but that
+in each successive generation there has been a tendency to reproduce the
+character in question, which at last, under unknown favourable conditions,
+gains an ascendancy.  For instance, it is probable that in each generation
+of the barb-pigeon, which produces most rarely a blue and black-barred
+bird, there has been a tendency in each generation in the plumage to assume
+this colour.  This view is hypothetical, but could be supported by some
+facts; and I can see no more abstract improbability in a tendency to
+produce any character being inherited for an endless number of generations,
+than in quite useless or rudimentary organs being, as we all know them to
+be, thus inherited.  Indeed, we may sometimes observe a mere tendency to
+produce a rudiment inherited:  for instance, in the common snapdragon
+(Antirrhinum) a rudiment of a fifth stamen so often appears, that this
+plant must have an inherited tendency to produce it.
+</para>
+
+<para>
+As all the species of the same genus are supposed, on my theory, to have
+descended from a common parent, it might be expected that they would
+occasionally vary in an analogous manner; so that a variety of one species
+would resemble in some of its characters another species; this other
+species being on my view only a well-marked and permanent variety.  But
+characters thus gained would probably be of an unimportant nature, for the
+presence of all important characters will be governed by natural selection,
+in accordance with the diverse habits of the species, and will not be left
+to the mutual action of the conditions of life and of a similar inherited
+constitution.  It might further be expected that the species of the same
+genus would occasionally exhibit reversions to lost ancestral characters. 
+As, however, we never know the exact character of the common ancestor of a
+group, we could not distinguish these two cases:  if, for instance, we did
+not know that the rock-pigeon was not feather-footed or turn-crowned, we
+could not have told, whether these characters in our domestic breeds were
+reversions or only analogous variations; but we might have inferred that
+the blueness was a case of reversion, from the number of the markings,
+which are correlated with the blue tint, and which it does not appear
+probable would all appear together from simple variation.  More especially
+we might have inferred this, from the blue colour and marks so often
+appearing when distinct breeds of diverse colours are crossed.  Hence,
+though under nature it must generally be left doubtful, what cases are
+reversions to an anciently existing character, and what are new but
+analogous variations, yet we ought, on my theory, sometimes to find the
+varying offspring of a species assuming characters (either from reversion
+or from analogous variation) which already occur in some other members of
+the same group.  And this undoubtedly is the case in nature.
+</para>
+
+<para>
+A considerable part of the difficulty in recognising a variable species in
+our systematic works, is due to its varieties mocking, as it were, some of
+the other species of the same genus.  A considerable catalogue, also, could
+be given of forms intermediate between two other forms, which themselves
+must be doubtfully ranked as either varieties or species; and this shows,
+unless all these forms be considered as independently created species, that
+the one in varying has assumed some of the characters of the other, so as
+to produce the intermediate form.  But the best evidence is afforded by
+parts or organs of an important and uniform nature occasionally varying so
+as to acquire, in some degree, the character of the same part or organ in
+an allied species.  I have collected a long list of such cases; but here,
+as before, I lie under a great disadvantage in not being able to give them. 
+I can only repeat that such cases certainly do occur, and seem to me very
+remarkable.
+</para>
+
+<para>
+I will, however, give one curious and complex case, not indeed as affecting
+any important character, but from occurring in several species of the same
+genus, partly under domestication and partly under nature.  It is a case
+apparently of reversion.  The ass not rarely has very distinct transverse
+bars on its legs, like those on the legs of a zebra:  it has been asserted
+that these are plainest in the foal, and from inquiries which I have made,
+I believe this to be true.  It has also been asserted that the stripe on
+each shoulder is sometimes double.  The shoulder stripe is certainly very
+variable in length and outline.  A white ass, but not an albino, has been
+described without either spinal or shoulder-stripe; and these stripes are
+sometimes very obscure, or actually quite lost, in dark-coloured asses. 
+The koulan of Pallas is said to have been seen with a double
+shoulder-stripe.  The hemionus has no shoulder-stripe; but traces of it, as
+stated by Mr. Blyth and others, occasionally appear:  and I have been
+informed by Colonel Poole that foals of this species are generally striped
+on the legs, and faintly on the shoulder.  The quagga, though so plainly
+barred like a zebra over the body, is without bars on the legs; but Dr.
+Gray has figured one specimen with very distinct zebra-like bars on the
+hocks.
+</para>
+
+<para>
+With respect to the horse, I have collected cases in England of the spinal
+stripe in horses of the most distinct breeds, and of all colours;
+transverse bars on the legs are not rare in duns, mouse-duns, and in one
+instance in a chestnut:  a faint shoulder-stripe may sometimes be seen in
+duns, and I have seen a trace in a bay horse.  My son made a careful
+examination and sketch for me of a dun Belgian cart-horse with a double
+stripe on each shoulder and with leg-stripes; and a man, whom I can
+implicitly trust, has examined for me a small dun Welch pony with three
+short parallel stripes on each shoulder.
+</para>
+
+<para>
+In the north-west part of India the Kattywar breed of horses is so
+generally striped, that, as I hear from Colonel Poole, who examined the
+breed for the Indian Government, a horse without stripes is not considered
+as purely-bred.  The spine is always striped; the legs are generally
+barred; and the shoulder-stripe, which is sometimes double and sometimes
+treble, is common; the side of the face, moreover, is sometimes striped. 
+The stripes are plainest in the foal; and sometimes quite disappear in old
+horses.  Colonel Poole has seen both gray and bay Kattywar horses striped
+when first foaled.  I have, also, reason to suspect, from information given
+me by Mr. W. W. Edwards, that with the English race-horse the spinal stripe
+is much commoner in the foal than in the full-grown animal.  Without here
+entering on further details, I may state that I have collected cases of leg
+and shoulder stripes in horses of very different breeds, in various
+countries from Britain to Eastern China; and from Norway in the north to
+the Malay Archipelago in the south.  In all parts of the world these
+stripes occur far oftenest in duns and mouse-duns; by the term dun a large
+range of colour is included, from one between brown and black to a close
+approach to cream-colour.
+</para>
+
+<para>
+I am aware that Colonel Hamilton Smith, who has written on this subject,
+believes that the several breeds of the horse have descended from several
+aboriginal species--one of which, the dun, was striped; and that the
+above-described appearances are all due to ancient crosses with the dun
+stock.  But I am not at all satisfied with this theory, and should be loth
+to apply it to breeds so distinct as the heavy Belgian cart-horse, Welch
+ponies, cobs, the lanky Kattywar race, &amp;c., inhabiting the most distant
+parts of the world.
+</para>
+
+<para>
+Now let us turn to the effects of crossing the several species of the
+horse-genus.  Rollin asserts, that the common mule from the ass and horse
+is particularly apt to have bars on its legs.  I once saw a mule with its
+legs so much striped that any one at first would have thought that it must
+have been the product of a zebra; and Mr. W. C. Martin, in his excellent
+treatise on the horse, has given a figure of a similar mule.  In four
+coloured drawings, which I have seen, of hybrids between the ass and zebra,
+the legs were much more plainly barred than the rest of the body; and in
+one of them there was a double shoulder-stripe.  In Lord Moreton's famous
+hybrid from a chestnut mare and male quagga, the hybrid, and even the pure
+offspring subsequently produced from the mare by a black Arabian sire, were
+much more plainly barred across the legs than is even the pure quagga. 
+Lastly, and this is another most remarkable case, a hybrid has been figured
+by Dr. Gray (and he informs me that he knows of a second case) from the ass
+and the hemionus; and this hybrid, though the ass seldom has stripes on its
+legs and the hemionus has none and has not even a shoulder-stripe,
+nevertheless had all four legs barred, and had three short
+shoulder-stripes, like those on the dun Welch pony, and even had some
+zebra-like stripes on the sides of its face.  With respect to this last
+fact, I was so convinced that not even a stripe of colour appears from what
+would commonly be called an accident, that I was led solely from the
+occurrence of the face-stripes on this hybrid from the ass and hemionus, to
+ask Colonel Poole whether such face-stripes ever occur in the eminently
+striped Kattywar breed of horses, and was, as we have seen, answered in the
+affirmative.
+</para>
+
+<para>
+What now are we to say to these several facts?  We see several very
+distinct species of the horse-genus becoming, by simple variation, striped
+on the legs like a zebra, or striped on the shoulders like an ass.  In the
+horse we see this tendency strong whenever a dun tint appears--a tint which
+approaches to that of the general colouring of the other species of the
+genus.  The appearance of the stripes is not accompanied by any change of
+form or by any other new character.  We see this tendency to become striped
+most strongly displayed in hybrids from between several of the most
+distinct species.  Now observe the case of the several breeds of pigeons: 
+they are descended from a pigeon (including two or three sub-species or
+geographical races) of a bluish colour, with certain bars and other marks;
+and when any breed assumes by simple variation a bluish tint, these bars
+and other marks invariably reappear; but without any other change of form
+or character.  When the oldest and truest breeds of various colours are
+crossed, we see a strong tendency for the blue tint and bars and marks to
+reappear in the mongrels.  I have stated that the most probable hypothesis
+to account for the reappearance of very ancient characters, is--that there
+is a tendency in the young of each successive generation to produce the
+long-lost character, and that this tendency, from unknown causes, sometimes
+prevails.  And we have just seen that in several species of the horse-genus
+the stripes are either plainer or appear more commonly in the young than in
+the old.  Call the breeds of pigeons, some of which have bred true for
+centuries, species; and how exactly parallel is the case with that of the
+species of the horse-genus!  For myself, I venture confidently to look back
+thousands on thousands of generations, and I see an animal striped like a
+zebra, but perhaps otherwise very differently constructed, the common
+parent of our domestic horse, whether or not it be descended from one or
+more wild stocks, of the ass, the hemionus, quagga, and zebra.
+</para>
+
+<para>
+He who believes that each equine species was independently created, will, I
+presume, assert that each species has been created with a tendency to vary,
+both under nature and under domestication, in this particular manner, so as
+often to become striped like other species of the genus; and that each has
+been created with a strong tendency, when crossed with species inhabiting
+distant quarters of the world, to produce hybrids resembling in their
+stripes, not their own parents, but other species of the genus.  To admit
+this view is, as it seems to me, to reject a real for an unreal, or at
+least for an unknown, cause.  It makes the works of God a mere mockery and
+deception; I would almost as soon believe with the old and ignorant
+cosmogonists, that fossil shells had never lived, but had been created in
+stone so as to mock the shells now living on the sea-shore.
+</para>
+
+<para>
+Summary. -- Our ignorance of the laws of variation is profound.  Not in one
+case out of a hundred can we pretend to assign any reason why this or that
+part differs, more or less, from the same part in the parents.  But
+whenever we have the means of instituting a comparison, the same laws
+appear to have acted in producing the lesser differences between varieties
+of the same species, and the greater differences between species of the
+same genus.  The external conditions of life, as climate and food, &amp;c.,
+seem to have induced some slight modifications.  Habit in producing
+constitutional differences, and use in strengthening, and disuse in
+weakening and diminishing organs, seem to have been more potent in their
+effects.  Homologous parts tend to vary in the same way, and homologous
+parts tend to cohere.  Modifications in hard parts and in external parts
+sometimes affect softer and internal parts.  When one part is largely
+developed, perhaps it tends to draw nourishment from the adjoining parts;
+and every part of the structure which can be saved without detriment to the
+individual, will be saved.  Changes of structure at an early age will
+generally affect parts subsequently developed; and there are very many
+other correlations of growth, the nature of which we are utterly unable to
+understand.  Multiple parts are variable in number and in structure,
+perhaps arising from such parts not having been closely specialised to any
+particular function, so that their modifications have not been closely
+checked by natural selection.  It is probably from this same cause that
+organic beings low in the scale of nature are more variable than those
+which have their whole organisation more specialised, and are higher in the
+scale.  Rudimentary organs, from being useless, will be disregarded by
+natural selection, and hence probably are variable.  Specific
+characters--that is, the characters which have come to differ since the
+several species of the same genus branched off from a common parent--are
+more variable than generic characters, or those which have long been
+inherited, and have not differed within this same period.  In these remarks
+we have referred to special parts or organs being still variable, because
+they have recently varied and thus come to differ; but we have also seen in
+the second Chapter that the same principle applies to the whole individual;
+for in a district where many species of any genus are found--that is, where
+there has been much former variation and differentiation, or where the
+manufactory of new specific forms has been actively at work--there, on an
+average, we now find most varieties or incipient species.  Secondary sexual
+characters are highly variable, and such characters differ much in the
+species of the same group.  Variability in the same parts of the
+organisation has generally been taken advantage of in giving secondary
+sexual differences to the sexes of the same species, and specific
+differences to the several species of the same genus.  Any part or organ
+developed to an extraordinary size or in an extraordinary manner, in
+comparison with the same part or organ in the allied species, must have
+gone through an extraordinary amount of modification since the genus arose;
+and thus we can understand why it should often still be variable in a much
+higher degree than other parts; for variation is a long-continued and slow
+process, and natural selection will in such cases not as yet have had time
+to overcome the tendency to further variability and to reversion to a less
+modified state.  But when a species with any extraordinarily-developed
+organ has become the parent of many modified descendants--which on my view
+must be a very slow process, requiring a long lapse of time--in this case,
+natural selection may readily have succeeded in giving a fixed character to
+the organ, in however extraordinary a manner it may be developed.  Species
+inheriting nearly the same constitution from a common parent and exposed to
+similar influences will naturally tend to present analogous variations, and
+these same species may occasionally revert to some of the characters of
+their ancient progenitors.  Although new and important modifications may
+not arise from reversion and analogous variation, such modifications will
+add to the beautiful and harmonious diversity of nature.
+</para>
+
+<para>
+Whatever the cause may be of each slight difference in the offspring from
+their parents--and a cause for each must exist--it is the steady
+accumulation, through natural selection, of such differences, when
+beneficial to the individual, that gives rise to all the more important
+modifications of structure, by which the innumerable beings on the face of
+this earth are enabled to struggle with each other, and the best adapted to
+survive.
+</para>
+
+</chapter>
+
+<chapter>
+<chapheader>
+
+<chapnum>Chapter VI</chapnum>
+
+<title>Difficulties on Theory</title>
+
+<chapsummary>
+Difficulties on the theory of descent with modification -- Transitions --
+Absence or rarity of transitional varieties -- Transitions in habits of
+life -- Diversified habits in the same species -- Species with habits
+widely different from those of their allies -- Organs of extreme perfection
+-- Means of transition -- Cases of difficulty -- Natura non facit saltum --
+Organs of small importance -- Organs not in all cases absolutely perfect --
+The law of Unity of Type and of the Conditions of Existence embraced by the
+theory of Natural Selection.
+</chapsummary>
+</chapheader>
+
+<para>
+Long before having arrived at this part of my work, a crowd of difficulties
+will have occurred to the reader.  Some of them are so grave that to this
+day I can never reflect on them without being staggered; but, to the best
+of my judgment, the greater number are only apparent, and those that are
+real are not, I think, fatal to my theory.
+</para>
+
+<para>
+These difficulties and objections may be classed under the following
+heads:- Firstly, why, if species have descended from other species by
+insensibly fine gradations, do we not everywhere see innumerable
+transitional forms?  Why is not all nature in confusion instead of the
+species being, as we see them, well defined?
+</para>
+
+<para>
+Secondly, is it possible that an animal having, for instance, the structure
+and habits of a bat, could have been formed by the modification of some
+animal with wholly different habits?  Can we believe that natural selection
+could produce, on the one hand, organs of trifling importance, such as the
+tail of a giraffe, which serves as a fly-flapper, and, on the other hand,
+organs of such wonderful structure, as the eye, of which we hardly as yet
+fully understand the inimitable perfection?
+</para>
+
+<para>
+Thirdly, can instincts be acquired and modified through natural selection? 
+What shall we say to so marvellous an instinct as that which leads the bee
+to make cells, which have practically anticipated the discoveries of
+profound mathematicians?
+</para>
+
+<para>
+Fourthly, how can we account for species, when crossed, being sterile and
+producing sterile offspring, whereas, when varieties are crossed, their
+fertility is unimpaired?
+</para>
+
+<para>
+The two first heads shall be here discussed--Instinct and Hybridism in
+separate chapters.
+</para>
+
+<para>
+On the absence or rarity of transitional varieties. -- As natural selection
+acts solely by the preservation of profitable modifications, each new form
+will tend in a fully-stocked country to take the place of, and finally to
+exterminate, its own less improved parent or other less-favoured forms with
+which it comes into competition.  Thus extinction and natural selection
+will, as we have seen, go hand in hand.  Hence, if we look at each species
+as descended from some other unknown form, both the parent and all the
+transitional varieties will generally have been exterminated by the very
+process of formation and perfection of the new form.
+</para>
+
+<para>
+But, as by this theory innumerable transitional forms must have existed,
+why do we not find them embedded in countless numbers in the crust of the
+earth?  It will be much more convenient to discuss this question in the
+chapter on the Imperfection of the geological record; and I will here only
+state that I believe the answer mainly lies in the record being
+incomparably less perfect than is generally supposed; the imperfection of
+the record being chiefly due to organic beings not inhabiting profound
+depths of the sea, and to their remains being embedded and preserved to a
+future age only in masses of sediment sufficiently thick and extensive to
+withstand an enormous amount of future degradation; and such fossiliferous
+masses can be accumulated only where much sediment is deposited on the
+shallow bed of the sea, whilst it slowly subsides.  These contingencies
+will concur only rarely, and after enormously long intervals.  Whilst the
+bed of the sea is stationary or is rising, or when very little sediment is
+being deposited, there will be blanks in our geological history.  The crust
+of the earth is a vast museum; but the natural collections have been made
+only at intervals of time immensely remote.
+</para>
+
+<para>
+But it may be urged that when several closely-allied species inhabit the
+same territory we surely ought to find at the present time many
+transitional forms.  Let us take a simple case:  in travelling from north
+to south over a continent, we generally meet at successive intervals with
+closely allied or representative species, evidently filling nearly the same
+place in the natural economy of the land.  These representative species
+often meet and interlock; and as the one becomes rarer and rarer, the other
+becomes more and more frequent, till the one replaces the other.  But if we
+compare these species where they intermingle, they are generally as
+absolutely distinct from each other in every detail of structure as are
+specimens taken from the metropolis inhabited by each.  By my theory these
+allied species have descended from a common parent; and during the process
+of modification, each has become adapted to the conditions of life of its
+own region, and has supplanted and exterminated its original parent and all
+the transitional varieties between its past and present states.  Hence we
+ought not to expect at the present time to meet with numerous transitional
+varieties in each region, though they must have existed there, and may be
+embedded there in a fossil condition.  But in the intermediate region,
+having intermediate conditions of life, why do we not now find
+closely-linking intermediate varieties?  This difficulty for a long time
+quite confounded me.  But I think it can be in large part explained.
+</para>
+
+<para>
+In the first place we should be extremely cautious in inferring, because an
+area is now continuous, that it has been continuous during a long period. 
+Geology would lead us to believe that almost every continent has been
+broken up into islands even during the later tertiary periods; and in such
+islands distinct species might have been separately formed without the
+possibility of intermediate varieties existing in the intermediate zones. 
+By changes in the form of the land and of climate, marine areas now
+continuous must often have existed within recent times in a far less
+continuous and uniform condition than at present.  But I will pass over
+this way of escaping from the difficulty; for I believe that many perfectly
+defined species have been formed on strictly continuous areas; though I do
+not doubt that the formerly broken condition of areas now continuous has
+played an important part in the formation of new species, more especially
+with freely-crossing and wandering animals.
+</para>
+
+<para>
+In looking at species as they are now distributed over a wide area, we
+generally find them tolerably numerous over a large territory, then
+becoming somewhat abruptly rarer and rarer on the confines, and finally
+disappearing.  Hence the neutral territory between two representative
+species is generally narrow in comparison with the territory proper to
+each.  We see the same fact in ascending mountains, and sometimes it is
+quite remarkable how abruptly, as Alph. De Candolle has observed, a common
+alpine species disappears.  The same fact has been noticed by Forbes in
+sounding the depths of the sea with the dredge.  To those who look at
+climate and the physical conditions of life as the all-important elements
+of distribution, these facts ought to cause surprise, as climate and height
+or depth graduate away insensibly.  But when we bear in mind that almost
+every species, even in its metropolis, would increase immensely in numbers,
+were it not for other competing species; that nearly all either prey on or
+serve as prey for others; in short, that each organic being is either
+directly or indirectly related in the most important manner to other
+organic beings, we must see that the range of the inhabitants of any
+country by no means exclusively depends on insensibly changing physical
+conditions, but in large part on the presence of other species, on which it
+depends, or by which it is destroyed, or with which it comes into
+competition; and as these species are already defined objects (however they
+may have become so), not blending one into another by insensible
+gradations, the range of any one species, depending as it does on the range
+of others, will tend to be sharply defined.  Moreover, each species on the
+confines of its range, where it exists in lessened numbers, will, during
+fluctuations in the number of its enemies or of its prey, or in the
+seasons, be extremely liable to utter extermination; and thus its
+geographical range will come to be still more sharply defined.
+</para>
+
+<para>
+If I am right in believing that allied or representative species, when
+inhabiting a continuous area, are generally so distributed that each has a
+wide range, with a comparatively narrow neutral territory between them, in
+which they become rather suddenly rarer and rarer; then, as varieties do
+not essentially differ from species, the same rule will probably apply to
+both; and if we in imagination adapt a varying species to a very large
+area, we shall have to adapt two varieties to two large areas, and a third
+variety to a narrow intermediate zone.  The intermediate variety,
+consequently, will exist in lesser numbers from inhabiting a narrow and
+lesser area; and practically, as far as I can make out, this rule holds
+good with varieties in a state of nature.  I have met with striking
+instances of the rule in the case of varieties intermediate between
+well-marked varieties in the genus Balanus.  And it would appear from
+information given me by Mr. Watson, Dr. Asa Gray, and Mr. Wollaston, that
+generally when varieties intermediate between two other forms occur, they
+are much rarer numerically than the forms which they connect.  Now, if we
+may trust these facts and inferences, and therefore conclude that varieties
+linking two other varieties together have generally existed in lesser
+numbers than the forms which they connect, then, I think, we can understand
+why intermediate varieties should not endure for very long periods;--why as
+a general rule they should be exterminated and disappear, sooner than the
+forms which they originally linked together.
+</para>
+
+<para>
+For any form existing in lesser numbers would, as already remarked, run a
+greater chance of being exterminated than one existing in large numbers;
+and in this particular case the intermediate form would be eminently liable
+to the inroads of closely allied forms existing on both sides of it.  But a
+far more important consideration, as I believe, is that, during the process
+of further modification, by which two varieties are supposed on my theory
+to be converted and perfected into two distinct species, the two which
+exist in larger numbers from inhabiting larger areas, will have a great
+advantage over the intermediate variety, which exists in smaller numbers in
+a narrow and intermediate zone.  For forms existing in larger numbers will
+always have a better chance, within any given period, of presenting further
+favourable variations for natural selection to seize on, than will the
+rarer forms which exist in lesser numbers.  Hence, the more common forms,
+in the race for life, will tend to beat and supplant the less common forms,
+for these will be more slowly modified and improved.  It is the same
+principle which, as I believe, accounts for the common species in each
+country, as shown in the second chapter, presenting on an average a greater
+number of well-marked varieties than do the rarer species.  I may
+illustrate what I mean by supposing three varieties of sheep to be kept,
+one adapted to an extensive mountainous region; a second to a comparatively
+narrow, hilly tract; and a third to wide plains at the base; and that the
+inhabitants are all trying with equal steadiness and skill to improve their
+stocks by selection; the chances in this case will be strongly in favour of
+the great holders on the mountains or on the plains improving their breeds
+more quickly than the small holders on the intermediate narrow, hilly
+tract; and consequently the improved mountain or plain breed will soon take
+the place of the less improved hill breed; and thus the two breeds, which
+originally existed in greater numbers, will come into close contact with
+each other, without the interposition of the supplanted, intermediate
+hill-variety.
+</para>
+
+<para>
+To sum up, I believe that species come to be tolerably well-defined
+objects, and do not at any one period present an inextricable chaos of
+varying and intermediate links:  firstly, because new varieties are very
+slowly formed, for variation is a very slow process, and natural selection
+can do nothing until favourable variations chance to occur, and until a
+place in the natural polity of the country can be better filled by some
+modification of some one or more of its inhabitants.  And such new places
+will depend on slow changes of climate, or on the occasional immigration of
+new inhabitants, and, probably, in a still more important degree, on some
+of the old inhabitants becoming slowly modified, with the new forms thus
+produced and the old ones acting and reacting on each other.  So that, in
+any one region and at any one time, we ought only to see a few species
+presenting slight modifications of structure in some degree permanent; and
+this assuredly we do see.
+</para>
+
+<para>
+Secondly, areas now continuous must often have existed within the recent
+period in isolated portions, in which many forms, more especially amongst
+the classes which unite for each birth and wander much, may have separately
+been rendered sufficiently distinct to rank as representative species.  In
+this case, intermediate varieties between the several representative
+species and their common parent, must formerly have existed in each broken
+portion of the land, but these links will have been supplanted and
+exterminated during the process of natural selection, so that they will no
+longer exist in a living state.
+</para>
+
+<para>
+Thirdly, when two or more varieties have been formed in different portions
+of a strictly continuous area, intermediate varieties will, it is probable,
+at first have been formed in the intermediate zones, but they will
+generally have had a short duration.  For these intermediate varieties
+will, from reasons already assigned (namely from what we know of the actual
+distribution of closely allied or representative species, and likewise of
+acknowledged varieties), exist in the intermediate zones in lesser numbers
+than the varieties which they tend to connect.  From this cause alone the
+intermediate varieties will be liable to accidental extermination; and
+during the process of further modification through natural selection, they
+will almost certainly be beaten and supplanted by the forms which they
+connect; for these from existing in greater numbers will, in the aggregate,
+present more variation, and thus be further improved through natural
+selection and gain further advantages.
+</para>
+
+<para>
+Lastly, looking not to any one time, but to all time, if my theory be true,
+numberless intermediate varieties, linking most closely all the species of
+the same group together, must assuredly have existed; but the very process
+of natural selection constantly tends, as has been so often remarked, to
+exterminate the parent forms and the intermediate links.  Consequently
+evidence of their former existence could be found only amongst fossil
+remains, which are preserved, as we shall in a future chapter attempt to
+show, in an extremely imperfect and intermittent record.
+</para>
+
+<para>
+On the origin and transitions of organic beings with peculiar habits and
+structure. -- It has been asked by the opponents of such views as I hold,
+how, for instance, a land carnivorous animal could have been converted into
+one with aquatic habits; for how could the animal in its transitional state
+have subsisted?  It would be easy to show that within the same group
+carnivorous animals exist having every intermediate grade between truly
+aquatic and strictly terrestrial habits; and as each exists by a struggle
+for life, it is clear that each is well adapted in its habits to its place
+in nature.  Look at the Mustela vison of North America, which has webbed
+feet and which resembles an otter in its fur, short legs, and form of tail;
+during summer this animal dives for and preys on fish, but during the long
+winter it leaves the frozen waters, and preys like other polecats on mice
+and land animals.  If a different case had been taken, and it had been
+asked how an insectivorous quadruped could possibly have been converted
+into a flying bat, the question would have been far more difficult, and I
+could have given no answer.  Yet I think such difficulties have very little
+weight.
+</para>
+
+<para>
+Here, as on other occasions, I lie under a heavy disadvantage, for out of
+the many striking cases which I have collected, I can give only one or two
+instances of transitional habits and structures in closely allied species
+of the same genus; and of diversified habits, either constant or
+occasional, in the same species.  And it seems to me that nothing less than
+a long list of such cases is sufficient to lessen the difficulty in any
+particular case like that of the bat.
+</para>
+
+<para>
+Look at the family of squirrels; here we have the finest gradation from
+animals with their tails only slightly flattened, and from others, as Sir
+J. Richardson has remarked, with the posterior part of their bodies rather
+wide and with the skin on their flanks rather full, to the so-called flying
+squirrels; and flying squirrels have their limbs and even the base of the
+tail united by a broad expanse of skin, which serves as a parachute and
+allows them to glide through the air to an astonishing distance from tree
+to tree.  We cannot doubt that each structure is of use to each kind of
+squirrel in its own country, by enabling it to escape birds or beasts of
+prey, or to collect food more quickly, or, as there is reason to believe,
+by lessening the danger from occasional falls.  But it does not follow from
+this fact that the structure of each squirrel is the best that it is
+possible to conceive under all natural conditions.  Let the climate and
+vegetation change, let other competing rodents or new beasts of prey
+immigrate, or old ones become modified, and all analogy would lead us to
+believe that some at least of the squirrels would decrease in numbers or
+become exterminated, unless they also became modified and improved in
+structure in a corresponding manner.  Therefore, I can see no difficulty,
+more especially under changing conditions of life, in the continued
+preservation of individuals with fuller and fuller flank-membranes, each
+modification being useful, each being propagated, until by the accumulated
+effects of this process of natural selection, a perfect so-called flying
+squirrel was produced.
+</para>
+
+<para>
+Now look at the Galeopithecus or flying lemur, which formerly was falsely
+ranked amongst bats.  It has an extremely wide flank-membrane, stretching
+from the corners of the jaw to the tail, and including the limbs and the
+elongated fingers:  the flank membrane is, also, furnished with an extensor
+muscle.  Although no graduated links of structure, fitted for gliding
+through the air, now connect the Galeopithecus with the other Lemuridae,
+yet I can see no difficulty in supposing that such links formerly existed,
+and that each had been formed by the same steps as in the case of the less
+perfectly gliding squirrels; and that each grade of structure had been
+useful to its possessor.  Nor can I see any insuperable difficulty in
+further believing it possible that the membrane-connected fingers and
+fore-arm of the Galeopithecus might be greatly lengthened by natural
+selection; and this, as far as the organs of flight are concerned, would
+convert it into a bat.  In bats which have the wing-membrane extended from
+the top of the shoulder to the tail, including the hind-legs, we perhaps
+see traces of an apparatus originally constructed for gliding through the
+air rather than for flight.
+</para>
+
+<para>
+If about a dozen genera of birds had become extinct or were unknown, who
+would have ventured to have surmised that birds might have existed which
+used their wings solely as flappers, like the logger-headed duck
+(Micropterus of Eyton); as fins in the water and front legs on the land,
+like the penguin; as sails, like the ostrich; and functionally for no
+purpose, like the Apteryx.  Yet the structure of each of these birds is
+good for it, under the conditions of life to which it is exposed, for each
+has to live by a struggle; but it is not necessarily the best possible
+under all possible conditions.  It must not be inferred from these remarks
+that any of the grades of wing-structure here alluded to, which perhaps may
+all have resulted from disuse, indicate the natural steps by which birds
+have acquired their perfect power of flight; but they serve, at least, to
+show what diversified means of transition are possible.
+</para>
+
+<para>
+Seeing that a few members of such water-breathing classes as the Crustacea
+and Mollusca are adapted to live on the land, and seeing that we have
+flying birds and mammals, flying insects of the most diversified types, and
+formerly had flying reptiles, it is conceivable that flying-fish, which now
+glide far through the air, slightly rising and turning by the aid of their
+fluttering fins, might have been modified into perfectly winged animals. 
+If this had been effected, who would have ever imagined that in an early
+transitional state they had been inhabitants of the open ocean, and had
+used their incipient organs of flight exclusively, as far as we know, to
+escape being devoured by other fish?
+</para>
+
+<para>
+When we see any structure highly perfected for any particular habit, as the
+wings of a bird for flight, we should bear in mind that animals displaying
+early transitional grades of the structure will seldom continue to exist to
+the present day, for they will have been supplanted by the very process of
+perfection through natural selection.  Furthermore, we may conclude that
+transitional grades between structures fitted for very different habits of
+life will rarely have been developed at an early period in great numbers
+and under many subordinate forms.  Thus, to return to our imaginary
+illustration of the flying-fish, it does not seem probable that fishes
+capable of true flight would have been developed under many subordinate
+forms, for taking prey of many kinds in many ways, on the land and in the
+water, until their organs of flight had come to a high stage of perfection,
+so as to have given them a decided advantage over other animals in the
+battle for life.  Hence the chance of discovering species with transitional
+grades of structure in a fossil condition will always be less, from their
+having existed in lesser numbers, than in the case of species with fully
+developed structures.
+</para>
+
+<para>
+I will now give two or three instances of diversified and of changed habits
+in the individuals of the same species.  When either case occurs, it would
+be easy for natural selection to fit the animal, by some modification of
+its structure, for its changed habits, or exclusively for one of its
+several different habits.  But it is difficult to tell, and immaterial for
+us, whether habits generally change first and structure afterwards; or
+whether slight modifications of structure lead to changed habits; both
+probably often change almost simultaneously.  Of cases of changed habits it
+will suffice merely to allude to that of the many British insects which now
+feed on exotic plants, or exclusively on artificial substances.  Of
+diversified habits innumerable instances could be given:  I have often
+watched a tyrant flycatcher (Saurophagus sulphuratus) in South America,
+hovering over one spot and then proceeding to another, like a kestrel, and
+at other times standing stationary on the margin of water, and then dashing
+like a kingfisher at a fish.  In our own country the larger titmouse (Parus
+major) may be seen climbing branches, almost like a creeper; it often, like
+a shrike, kills small birds by blows on the head; and I have many times
+seen and heard it hammering the seeds of the yew on a branch, and thus
+breaking them like a nuthatch.  In North America the black bear was seen by
+Hearne swimming for hours with widely open mouth, thus catching, like a
+whale, insects in the water.  Even in so extreme a case as this, if the
+supply of insects were constant, and if better adapted competitors did not
+already exist in the country, I can see no difficulty in a race of bears
+being rendered, by natural selection, more and more aquatic in their
+structure and habits, with larger and larger mouths, till a creature was
+produced as monstrous as a whale.
+</para>
+
+<para>
+As we sometimes see individuals of a species following habits widely
+different from those both of their own species and of the other species of
+the same genus, we might expect, on my theory, that such individuals would
+occasionally have given rise to new species, having anomalous habits, and
+with their structure either slightly or considerably modified from that of
+their proper type.  And such instances do occur in nature.  Can a more
+striking instance of adaptation be given than that of a woodpecker for
+climbing trees and for seizing insects in the chinks of the bark?  Yet in
+North America there are woodpeckers which feed largely on fruit, and others
+with elongated wings which chase insects on the wing; and on the plains of
+La Plata, where not a tree grows, there is a woodpecker, which in every
+essential part of its organisation, even in its colouring, in the harsh
+tone of its voice, and undulatory flight, told me plainly of its close
+blood-relationship to our common species; yet it is a woodpecker which
+never climbs a tree!
+</para>
+
+<para>
+Petrels are the most aerial and oceanic of birds, yet in the quiet Sounds
+of Tierra del Fuego, the Puffinuria berardi, in its general habits, in its
+astonishing power of diving, its manner of swimming, and of flying when
+unwillingly it takes flight, would be mistaken by any one for an auk or
+grebe; nevertheless, it is essentially a petrel, but with many parts of its
+organisation profoundly modified.  On the other hand, the acutest observer
+by examining the dead body of the water-ouzel would never have suspected
+its sub-aquatic habits; yet this anomalous member of the strictly
+terrestrial thrush family wholly subsists by diving,--grasping the stones
+with its feet and using its wings under water.
+</para>
+
+<para>
+He who believes that each being has been created as we now see it, must
+occasionally have felt surprise when he has met with an animal having
+habits and structure not at all in agreement.  What can be plainer than
+that the webbed feet of ducks and geese are formed for swimming? yet there
+are upland geese with webbed feet which rarely or never go near the water;
+and no one except Audubon has seen the frigate-bird, which has all its four
+toes webbed, alight on the surface of the sea.  On the other hand, grebes
+and coots are eminently aquatic, although their toes are only bordered by
+membrane.  What seems plainer than that the long toes of grallatores are
+formed for walking over swamps and floating plants, yet the water-hen is
+nearly as aquatic as the coot; and the landrail nearly as terrestrial as
+the quail or partridge.  In such cases, and many others could be given,
+habits have changed without a corresponding change of structure.  The
+webbed feet of the upland goose may be said to have become rudimentary in
+function, though not in structure.  In the frigate-bird, the deeply-scooped
+membrane between the toes shows that structure has begun to change.
+</para>
+
+<para>
+He who believes in separate and innumerable acts of creation will say, that
+in these cases it has pleased the Creator to cause a being of one type to
+take the place of one of another type; but this seems to me only restating
+the fact in dignified language.  He who believes in the struggle for
+existence and in the principle of natural selection, will acknowledge that
+every organic being is constantly endeavouring to increase in numbers; and
+that if any one being vary ever so little, either in habits or structure,
+and thus gain an advantage over some other inhabitant of the country, it
+will seize on the place of that inhabitant, however different it may be
+from its own place.  Hence it will cause him no surprise that there should
+be geese and frigate-birds with webbed feet, either living on the dry land
+or most rarely alighting on the water; that there should be long-toed
+corncrakes living in meadows instead of in swamps; that there should be
+woodpeckers where not a tree grows; that there should be diving thrushes,
+and petrels with the habits of auks.
+</para>
+
+<para>
+Organs of extreme perfection and complication. -- To suppose that the eye,
+with all its inimitable contrivances for adjusting the focus to different
+distances, for admitting different amounts of light, and for the correction
+of spherical and chromatic aberration, could have been formed by natural
+selection, seems, I freely confess, absurd in the highest possible degree. 
+Yet reason tells me, that if numerous gradations from a perfect and complex
+eye to one very imperfect and simple, each grade being useful to its
+possessor, can be shown to exist; if further, the eye does vary ever so
+slightly, and the variations be inherited, which is certainly the case; and
+if any variation or modification in the organ be ever useful to an animal
+under changing conditions of life, then the difficulty of believing that a
+perfect and complex eye could be formed by natural selection, though
+insuperable by our imagination, can hardly be considered real.  How a nerve
+comes to be sensitive to light, hardly concerns us more than how life
+itself first originated; but I may remark that several facts make me
+suspect that any sensitive nerve may be rendered sensitive to light, and
+likewise to those coarser vibrations of the air which produce sound.
+</para>
+
+<para>
+In looking for the gradations by which an organ in any species has been
+perfected, we ought to look exclusively to its lineal ancestors; but this
+is scarcely ever possible, and we are forced in each case to look to
+species of the same group, that is to the collateral descendants from the
+same original parent-form, in order to see what gradations are possible,
+and for the chance of some gradations having been transmitted from the
+earlier stages of descent, in an unaltered or little altered condition. 
+Amongst existing Vertebrata, we find but a small amount of gradation in the
+structure of the eye, and from fossil species we can learn nothing on this
+head.  In this great class we should probably have to descend far beneath
+the lowest known fossiliferous stratum to discover the earlier stages, by
+which the eye has been perfected.
+</para>
+
+<para>
+In the Articulata we can commence a series with an optic nerve merely
+coated with pigment, and without any other mechanism; and from this low
+stage, numerous gradations of structure, branching off in two fundamentally
+different lines, can be shown to exist, until we reach a moderately high
+stage of perfection.  In certain crustaceans, for instance, there is a
+double cornea, the inner one divided into facets, within each of which
+there is a lens-shaped swelling.  In other crustaceans the transparent
+cones which are coated by pigment, and which properly act only by excluding
+lateral pencils of light, are convex at their upper ends and must act by
+convergence; and at their lower ends there seems to be an imperfect
+vitreous substance.  With these facts, here far too briefly and imperfectly
+given, which show that there is much graduated diversity in the eyes of
+living crustaceans, and bearing in mind how small the number of living
+animals is in proportion to those which have become extinct, I can see no
+very great difficulty (not more than in the case of many other structures)
+in believing that natural selection has converted the simple apparatus of
+an optic nerve merely coated with pigment and invested by transparent
+membrane, into an optical instrument as perfect as is possessed by any
+member of the great Articulate class.
+</para>
+
+<para>
+He who will go thus far, if he find on finishing this treatise that large
+bodies of facts, otherwise inexplicable, can be explained by the theory of
+descent, ought not to hesitate to go further, and to admit that a structure
+even as perfect as the eye of an eagle might be formed by natural
+selection, although in this case he does not know any of the transitional
+grades.  His reason ought to conquer his imagination; though I have felt
+the difficulty far too keenly to be surprised at any degree of hesitation
+in extending the principle of natural selection to such startling lengths.
+</para>
+
+<para>
+It is scarcely possible to avoid comparing the eye to a telescope.  We know
+that this instrument has been perfected by the long-continued efforts of
+the highest human intellects; and we naturally infer that the eye has been
+formed by a somewhat analogous process.  But may not this inference be
+presumptuous?  Have we any right to assume that the Creator works by
+intellectual powers like those of man?  If we must compare the eye to an
+optical instrument, we ought in imagination to take a thick layer of
+transparent tissue, with a nerve sensitive to light beneath, and then
+suppose every part of this layer to be continually changing slowly in
+density, so as to separate into layers of different densities and
+thicknesses, placed at different distances from each other, and with the
+surfaces of each layer slowly changing in form.  Further we must suppose
+that there is a power always intently watching each slight accidental
+alteration in the transparent layers; and carefully selecting each
+alteration which, under varied circumstances, may in any way, or in any
+degree, tend to produce a distincter image.  We must suppose each new state
+of the instrument to be multiplied by the million; and each to be preserved
+till a better be produced, and then the old ones to be destroyed.  In
+living bodies, variation will cause the slight alterations, generation will
+multiply them almost infinitely, and natural selection will pick out with
+unerring skill each improvement.  Let this process go on for millions on
+millions of years; and during each year on millions of individuals of many
+kinds; and may we not believe that a living optical instrument might thus
+be formed as superior to one of glass, as the works of the Creator are to
+those of man?
+</para>
+
+<para>
+If it could be demonstrated that any complex organ existed, which could not
+possibly have been formed by numerous, successive, slight modifications, my
+theory would absolutely break down.  But I can find out no such case.  No
+doubt many organs exist of which we do not know the transitional grades,
+more especially if we look to much-isolated species, round which, according
+to my theory, there has been much extinction.  Or again, if we look to an
+organ common to all the members of a large class, for in this latter case
+the organ must have been first formed at an extremely remote period, since
+which all the many members of the class have been developed; and in order
+to discover the early transitional grades through which the organ has
+passed, we should have to look to very ancient ancestral forms, long since
+become extinct.
+</para>
+
+<para>
+We should be extremely cautious in concluding that an organ could not have
+been formed by transitional gradations of some kind.  Numerous cases could
+be given amongst the lower animals of the same organ performing at the same
+time wholly distinct functions; thus the alimentary canal respires,
+digests, and excretes in the larva of the dragon-fly and in the fish
+Cobites.  In the Hydra, the animal may be turned inside out, and the
+exterior surface will then digest and the stomach respire.  In such cases
+natural selection might easily specialise, if any advantage were thus
+gained, a part or organ, which had performed two functions, for one
+function alone, and thus wholly change its nature by insensible steps.  Two
+distinct organs sometimes perform simultaneously the same function in the
+same individual; to give one instance, there are fish with gills or
+branchiae that breathe the air dissolved in the water, at the same time
+that they breathe free air in their swimbladders, this latter organ having
+a ductus pneumaticus for its supply, and being divided by highly vascular
+partitions.  In these cases, one of the two organs might with ease be
+modified and perfected so as to perform all the work by itself, being aided
+during the process of modification by the other organ; and then this other
+organ might be modified for some other and quite distinct purpose, or be
+quite obliterated.
+</para>
+
+<para>
+The illustration of the swimbladder in fishes is a good one, because it
+shows us clearly the highly important fact that an organ originally
+constructed for one purpose, namely flotation, may be converted into one
+for a wholly different purpose, namely respiration.  The swimbladder has,
+also, been worked in as an accessory to the auditory organs of certain
+fish, or, for I do not know which view is now generally held, a part of the
+auditory apparatus has been worked in as a complement to the swimbladder. 
+All physiologists admit that the swimbladder is homologous, or 'ideally
+similar,' in position and structure with the lungs of the higher vertebrate
+animals:  hence there seems to me to be no great difficulty in believing
+that natural selection has actually converted a swimbladder into a lung, or
+organ used exclusively for respiration.
+</para>
+
+<para>
+I can, indeed, hardly doubt that all vertebrate animals having true lungs
+have descended by ordinary generation from an ancient prototype, of which
+we know nothing, furnished with a floating apparatus or swimbladder.  We
+can thus, as I infer from Professor Owen's interesting description of these
+parts, understand the strange fact that every particle of food and drink
+which we swallow has to pass over the orifice of the trachea, with some
+risk of falling into the lungs, notwithstanding the beautiful contrivance
+by which the glottis is closed.  In the higher Vertebrata the branchiae
+have wholly disappeared--the slits on the sides of the neck and the
+loop-like course of the arteries still marking in the embryo their former
+position.  But it is conceivable that the now utterly lost branchiae might
+have been gradually worked in by natural selection for some quite distinct
+purpose:  in the same manner as, on the view entertained by some
+naturalists that the branchiae and dorsal scales of Annelids are homologous
+with the wings and wing-covers of insects, it is probable that organs which
+at a very ancient period served for respiration have been actually
+converted into organs of flight.
+</para>
+
+<para>
+In considering transitions of organs, it is so important to bear in mind
+the probability of conversion from one function to another, that I will
+give one more instance.  Pedunculated cirripedes have two minute folds of
+skin, called by me the ovigerous frena, which serve, through the means of a
+sticky secretion, to retain the eggs until they are hatched within the
+sack.  These cirripedes have no branchiae, the whole surface of the body
+and sack, including the small frena, serving for respiration.  The
+Balanidae or sessile cirripedes, on the other hand, have no ovigerous
+frena, the eggs lying loose at the bottom of the sack, in the well-enclosed
+shell; but they have large folded branchiae.  Now I think no one will
+dispute that the ovigerous frena in the one family are strictly homologous
+with the branchiae of the other family; indeed, they graduate into each
+other.  Therefore I do not doubt that little folds of skin, which
+originally served as ovigerous frena, but which, likewise, very slightly
+aided the act of respiration, have been gradually converted by natural
+selection into branchiae, simply through an increase in their size and the
+obliteration of their adhesive glands.  If all pedunculated cirripedes had
+become extinct, and they have already suffered far more extinction than
+have sessile cirripedes, who would ever have imagined that the branchiae in
+this latter family had originally existed as organs for preventing the ova
+from being washed out of the sack?
+</para>
+
+<para>
+Although we must be extremely cautious in concluding that any organ could
+not possibly have been produced by successive transitional gradations, yet,
+undoubtedly, grave cases of difficulty occur, some of which will be
+discussed in my future work.
+</para>
+
+<para>
+One of the gravest is that of neuter insects, which are often very
+differently constructed from either the males or fertile females; but this
+case will be treated of in the next chapter.  The electric organs of fishes
+offer another case of special difficulty; it is impossible to conceive by
+what steps these wondrous organs have been produced; but, as Owen and
+others have remarked, their intimate structure closely resembles that of
+common muscle; and as it has lately been shown that Rays have an organ
+closely analogous to the electric apparatus, and yet do not, as Matteuchi
+asserts, discharge any electricity, we must own that we are far too
+ignorant to argue that no transition of any kind is possible.
+</para>
+
+<para>
+The electric organs offer another and even more serious difficulty; for
+they occur in only about a dozen fishes, of which several are widely remote
+in their affinities.  Generally when the same organ appears in several
+members of the same class, especially if in members having very different
+habits of life, we may attribute its presence to inheritance from a common
+ancestor; and its absence in some of the members to its loss through disuse
+or natural selection.  But if the electric organs had been inherited from
+one ancient progenitor thus provided, we might have expected that all
+electric fishes would have been specially related to each other.  Nor does
+geology at all lead to the belief that formerly most fishes had electric
+organs, which most of their modified descendants have lost.  The presence
+of luminous organs in a few insects, belonging to different families and
+orders, offers a parallel case of difficulty.  Other cases could be given;
+for instance in plants, the very curious contrivance of a mass of
+pollen-grains, borne on a foot-stalk with a sticky gland at the end, is the
+same in Orchis and Asclepias,--genera almost as remote as possible amongst
+flowering plants.  In all these cases of two very distinct species
+furnished with apparently the same anomalous organ, it should be observed
+that, although the general appearance and function of the organ may be the
+same, yet some fundamental difference can generally be detected.  I am
+inclined to believe that in nearly the same way as two men have sometimes
+independently hit on the very same invention, so natural selection, working
+for the good of each being and taking advantage of analogous variations,
+has sometimes modified in very nearly the same manner two parts in two
+organic beings, which owe but little of their structure in common to
+inheritance from the same ancestor.
+</para>
+
+<para>
+Although in many cases it is most difficult to conjecture by what
+transitions an organ could have arrived at its present state; yet,
+considering that the proportion of living and known forms to the extinct
+and unknown is very small, I have been astonished how rarely an organ can
+be named, towards which no transitional grade is known to lead.  The truth
+of this remark is indeed shown by that old canon in natural history of
+'Natura non facit saltum.'  We meet with this admission in the writings of
+almost every experienced naturalist; or, as Milne Edwards has well
+expressed it, nature is prodigal in variety, but niggard in innovation. 
+Why, on the theory of Creation, should this be so?  Why should all the
+parts and organs of many independent beings, each supposed to have been
+separately created for its proper place in nature, be so invariably linked
+together by graduated steps?  Why should not Nature have taken a leap from
+structure to structure?  On the theory of natural selection, we can clearly
+understand why she should not; for natural selection can act only by taking
+advantage of slight successive variations; she can never take a leap, but
+must advance by the shortest and slowest steps.
+</para>
+
+<para>
+Organs of little apparent importance. -- As natural selection acts by life
+and death,--by the preservation of individuals with any favourable
+variation, and by the destruction of those with any unfavourable deviation
+of structure,--I have sometimes felt much difficulty in understanding the
+origin of simple parts, of which the importance does not seem sufficient to
+cause the preservation of successively varying individuals.  I have
+sometimes felt as much difficulty, though of a very different kind, on this
+head, as in the case of an organ as perfect and complex as the eye.
+</para>
+
+<para>
+In the first place, we are much too ignorant in regard to the whole economy
+of any one organic being, to say what slight modifications would be of
+importance or not.  In a former chapter I have given instances of most
+trifling characters, such as the down on fruit and the colour of the flesh,
+which, from determining the attacks of insects or from being correlated
+with constitutional differences, might assuredly be acted on by natural
+selection.  The tail of the giraffe looks like an artificially constructed
+fly-flapper; and it seems at first incredible that this could have been
+adapted for its present purpose by successive slight modifications, each
+better and better, for so trifling an object as driving away flies; yet we
+should pause before being too positive even in this case, for we know that
+the distribution and existence of cattle and other animals in South America
+absolutely depends on their power of resisting the attacks of insects:  so
+that individuals which could by any means defend themselves from these
+small enemies, would be able to range into new pastures and thus gain a
+great advantage.  It is not that the larger quadrupeds are actually
+destroyed (except in some rare cases) by the flies, but they are
+incessantly harassed and their strength reduced, so that they are more
+subject to disease, or not so well enabled in a coming dearth to search for
+food, or to escape from beasts of prey.
+</para>
+
+<para>
+Organs now of trifling importance have probably in some cases been of high
+importance to an early progenitor, and, after having been slowly perfected
+at a former period, have been transmitted in nearly the same state,
+although now become of very slight use; and any actually injurious
+deviations in their structure will always have been checked by natural
+selection.  Seeing how important an organ of locomotion the tail is in most
+aquatic animals, its general presence and use for many purposes in so many
+land animals, which in their lungs or modified swim-bladders betray their
+aquatic origin, may perhaps be thus accounted for.  A well-developed tail
+having been formed in an aquatic animal, it might subsequently come to be
+worked in for all sorts of purposes, as a fly-flapper, an organ of
+prehension, or as an aid in turning, as with the dog, though the aid must
+be slight, for the hare, with hardly any tail, can double quickly enough.
+</para>
+
+<para>
+In the second place, we may sometimes attribute importance to characters
+which are really of very little importance, and which have originated from
+quite secondary causes, independently of natural selection.  We should
+remember that climate, food, &amp;c., probably have some little direct
+influence on the organisation; that characters reappear from the law of
+reversion; that correlation of growth will have had a most important
+influence in modifying various structures; and finally, that sexual
+selection will often have largely modified the external characters of
+animals having a will, to give one male an advantage in fighting with
+another or in charming the females.  Moreover when a modification of
+structure has primarily arisen from the above or other unknown causes, it
+may at first have been of no advantage to the species, but may subsequently
+have been taken advantage of by the descendants of the species under new
+conditions of life and with newly acquired habits.
+</para>
+
+<para>
+To give a few instances to illustrate these latter remarks.  If green
+woodpeckers alone had existed, and we did not know that there were many
+black and pied kinds, I dare say that we should have thought that the green
+colour was a beautiful adaptation to hide this tree-frequenting bird from
+its enemies; and consequently that it was a character of importance and
+might have been acquired through natural selection; as it is, I have no
+doubt that the colour is due to some quite distinct cause, probably to
+sexual selection.  A trailing bamboo in the Malay Archipelago climbs the
+loftiest trees by the aid of exquisitely constructed hooks clustered around
+the ends of the branches, and this contrivance, no doubt, is of the highest
+service to the plant; but as we see nearly similar hooks on many trees
+which are not climbers, the hooks on the bamboo may have arisen from
+unknown laws of growth, and have been subsequently taken advantage of by
+the plant undergoing further modification and becoming a climber.  The
+naked skin on the head of a vulture is generally looked at as a direct
+adaptation for wallowing in putridity; and so it may be, or it may possibly
+be due to the direct action of putrid matter; but we should be very
+cautious in drawing any such inference, when we see that the skin on the
+head of the clean-feeding male turkey is likewise naked.  The sutures in
+the skulls of young mammals have been advanced as a beautiful adaptation
+for aiding parturition, and no doubt they facilitate, or may be
+indispensable for this act; but as sutures occur in the skulls of young
+birds and reptiles, which have only to escape from a broken egg, we may
+infer that this structure has arisen from the laws of growth, and has been
+taken advantage of in the parturition of the higher animals.
+</para>
+
+<para>
+We are profoundly ignorant of the causes producing slight and unimportant
+variations; and we are immediately made conscious of this by reflecting on
+the differences in the breeds of our domesticated animals in different
+countries,--more especially in the less civilized countries where there has
+been but little artificial selection.  Careful observers are convinced that
+a damp climate affects the growth of the hair, and that with the hair the
+horns are correlated.  Mountain breeds always differ from lowland breeds;
+and a mountainous country would probably affect the hind limbs from
+exercising them more, and possibly even the form of the pelvis; and then by
+the law of homologous variation, the front limbs and even the head would
+probably be affected.  The shape, also, of the pelvis might affect by
+pressure the shape of the head of the young in the womb.  The laborious
+breathing necessary in high regions would, we have some reason to believe,
+increase the size of the chest; and again correlation would come into play. 
+Animals kept by savages in different countries often have to struggle for
+their own subsistence, and would be exposed to a certain extent to natural
+selection, and individuals with slightly different constitutions would
+succeed best under different climates; and there is reason to believe that
+constitution and colour are correlated.  A good observer, also, states that
+in cattle susceptibility to the attacks of flies is correlated with colour,
+as is the liability to be poisoned by certain plants; so that colour would
+be thus subjected to the action of natural selection.  But we are far too
+ignorant to speculate on the relative importance of the several known and
+unknown laws of variation; and I have here alluded to them only to show
+that, if we are unable to account for the characteristic differences of our
+domestic breeds, which nevertheless we generally admit to have arisen
+through ordinary generation, we ought not to lay too much stress on our
+ignorance of the precise cause of the slight analogous differences between
+species.  I might have adduced for this same purpose the differences
+between the races of man, which are so strongly marked; I may add that some
+little light can apparently be thrown on the origin of these differences,
+chiefly through sexual selection of a particular kind, but without here
+entering on copious details my reasoning would appear frivolous.
+</para>
+
+<para>
+The foregoing remarks lead me to say a few words on the protest lately made
+by some naturalists, against the utilitarian doctrine that every detail of
+structure has been produced for the good of its possessor.  They believe
+that very many structures have been created for beauty in the eyes of man,
+or for mere variety.  This doctrine, if true, would be absolutely fatal to
+my theory.  Yet I fully admit that many structures are of no direct use to
+their possessors.  Physical conditions probably have had some little effect
+on structure, quite independently of any good thus gained.  Correlation of
+growth has no doubt played a most important part, and a useful modification
+of one part will often have entailed on other parts diversified changes of
+no direct use.  So again characters which formerly were useful, or which
+formerly had arisen from correlation of growth, or from other unknown
+cause, may reappear from the law of reversion, though now of no direct use. 
+The effects of sexual selection, when displayed in beauty to charm the
+females, can be called useful only in rather a forced sense.  But by far
+the most important consideration is that the chief part of the organisation
+of every being is simply due to inheritance; and consequently, though each
+being assuredly is well fitted for its place in nature, many structures now
+have no direct relation to the habits of life of each species.  Thus, we
+can hardly believe that the webbed feet of the upland goose or of the
+frigate-bird are of special use to these birds; we cannot believe that the
+same bones in the arm of the monkey, in the fore leg of the horse, in the
+wing of the bat, and in the flipper of the seal, are of special use to
+these animals.  We may safely attribute these structures to inheritance. 
+But to the progenitor of the upland goose and of the frigate-bird, webbed
+feet no doubt were as useful as they now are to the most aquatic of
+existing birds.  So we may believe that the progenitor of the seal had not
+a flipper, but a foot with five toes fitted for walking or grasping; and we
+may further venture to believe that the several bones in the limbs of the
+monkey, horse, and bat, which have been inherited from a common progenitor,
+were formerly of more special use to that progenitor, or its progenitors,
+than they now are to these animals having such widely diversified habits. 
+Therefore we may infer that these several bones might have been acquired
+through natural selection, subjected formerly, as now, to the several laws
+of inheritance, reversion, correlation of growth, &amp;c.  Hence every detail
+of structure in every living creature (making some little allowance for the
+direct action of physical conditions) may be viewed, either as having been
+of special use to some ancestral form, or as being now of special use to
+the descendants of this form--either directly, or indirectly through the
+complex laws of growth.
+</para>
+
+<para>
+Natural selection cannot possibly produce any modification in any one
+species exclusively for the good of another species; though throughout
+nature one species incessantly takes advantage of, and profits by, the
+structure of another.  But natural selection can and does often produce
+structures for the direct injury of other species, as we see in the fang of
+the adder, and in the ovipositor of the ichneumon, by which its eggs are
+deposited in the living bodies of other insects.  If it could be proved
+that any part of the structure of any one species had been formed for the
+exclusive good of another species, it would annihilate my theory, for such
+could not have been produced through natural selection.  Although many
+statements may be found in works on natural history to this effect, I
+cannot find even one which seems to me of any weight.  It is admitted that
+the rattlesnake has a poison-fang for its own defence and for the
+destruction of its prey; but some authors suppose that at the same time
+this snake is furnished with a rattle for its own injury, namely, to warn
+its prey to escape.  I would almost as soon believe that the cat curls the
+end of its tail when preparing to spring, in order to warn the doomed
+mouse.  But I have not space here to enter on this and other such cases.
+</para>
+
+<para>
+Natural selection will never produce in a being anything injurious to
+itself, for natural selection acts solely by and for the good of each.  No
+organ will be formed, as Paley has remarked, for the purpose of causing
+pain or for doing an injury to its possessor.  If a fair balance be struck
+between the good and evil caused by each part, each will be found on the
+whole advantageous.  After the lapse of time, under changing conditions of
+life, if any part comes to be injurious, it will be modified; or if it be
+not so, the being will become extinct, as myriads have become extinct.
+</para>
+
+<para>
+Natural selection tends only to make each organic being as perfect as, or
+slightly more perfect than, the other inhabitants of the same country with
+which it has to struggle for existence.  And we see that this is the degree
+of perfection attained under nature.  The endemic productions of New
+Zealand, for instance, are perfect one compared with another; but they are
+now rapidly yielding before the advancing legions of plants and animals
+introduced from Europe.  Natural selection will not produce absolute
+perfection, nor do we always meet, as far as we can judge, with this high
+standard under nature.  The correction for the aberration of light is said,
+on high authority, not to be perfect even in that most perfect organ, the
+eye.  If our reason leads us to admire with enthusiasm a multitude of
+inimitable contrivances in nature, this same reason tells us, though we may
+easily err on both sides, that some other contrivances are less perfect. 
+Can we consider the sting of the wasp or of the bee as perfect, which, when
+used against many attacking animals, cannot be withdrawn, owing to the
+backward serratures, and so inevitably causes the death of the insect by
+tearing out its viscera?
+</para>
+
+<para>
+If we look at the sting of the bee, as having originally existed in a
+remote progenitor as a boring and serrated instrument, like that in so many
+members of the same great order, and which has been modified but not
+perfected for its present purpose, with the poison originally adapted to
+cause galls subsequently intensified, we can perhaps understand how it is
+that the use of the sting should so often cause the insect's own death: 
+for if on the whole the power of stinging be useful to the community, it
+will fulfil all the requirements of natural selection, though it may cause
+the death of some few members.  If we admire the truly wonderful power of
+scent by which the males of many insects find their females, can we admire
+the production for this single purpose of thousands of drones, which are
+utterly useless to the community for any other end, and which are
+ultimately slaughtered by their industrious and sterile sisters?  It may be
+difficult, but we ought to admire the savage instinctive hatred of the
+queen-bee, which urges her instantly to destroy the young queens her
+daughters as soon as born, or to perish herself in the combat; for
+undoubtedly this is for the good of the community; and maternal love or
+maternal hatred, though the latter fortunately is most rare, is all the
+same to the inexorable principle of natural selection.  If we admire the
+several ingenious contrivances, by which the flowers of the orchis and of
+many other plants are fertilised through insect agency, can we consider as
+equally perfect the elaboration by our fir-trees of dense clouds of pollen,
+in order that a few granules may be wafted by a chance breeze on to the
+ovules?
+</para>
+
+<para>
+Summary of Chapter -- We have in this chapter discussed some of the
+difficulties and objections which may be urged against my theory.  Many of
+them are very grave; but I think that in the discussion light has been
+thrown on several facts, which on the theory of independent acts of
+creation are utterly obscure.  We have seen that species at any one period
+are not indefinitely variable, and are not linked together by a multitude
+of intermediate gradations, partly because the process of natural selection
+will always be very slow, and will act, at any one time, only on a very few
+forms; and partly because the very process of natural selection almost
+implies the continual supplanting and extinction of preceding and
+intermediate gradations.  Closely allied species, now living on a
+continuous area, must often have been formed when the area was not
+continuous, and when the conditions of life did not insensibly graduate
+away from one part to another.  When two varieties are formed in two
+districts of a continuous area, an intermediate variety will often be
+formed, fitted for an intermediate zone; but from reasons assigned, the
+intermediate variety will usually exist in lesser numbers than the two
+forms which it connects; consequently the two latter, during the course of
+further modification, from existing in greater numbers, will have a great
+advantage over the less numerous intermediate variety, and will thus
+generally succeed in supplanting and exterminating it.
+</para>
+
+<para>
+We have seen in this chapter how cautious we should be in concluding that
+the most different habits of life could not graduate into each other; that
+a bat, for instance, could not have been formed by natural selection from
+an animal which at first could only glide through the air.
+</para>
+
+<para>
+We have seen that a species may under new conditions of life change its
+habits, or have diversified habits, with some habits very unlike those of
+its nearest congeners.  Hence we can understand, bearing in mind that each
+organic being is trying to live wherever it can live, how it has arisen
+that there are upland geese with webbed feet, ground woodpeckers, diving
+thrushes, and petrels with the habits of auks.
+</para>
+
+<para>
+Although the belief that an organ so perfect as the eye could have been
+formed by natural selection, is more than enough to stagger any one; yet in
+the case of any organ, if we know of a long series of gradations in
+complexity, each good for its possessor, then, under changing conditions of
+life, there is no logical impossibility in the acquirement of any
+conceivable degree of perfection through natural selection.  In the cases
+in which we know of no intermediate or transitional states, we should be
+very cautious in concluding that none could have existed, for the
+homologies of many organs and their intermediate states show that wonderful
+metamorphoses in function are at least possible.  For instance, a
+swim-bladder has apparently been converted into an air-breathing lung.  The
+same organ having performed simultaneously very different functions, and
+then having been specialised for one function; and two very distinct organs
+having performed at the same time the same function, the one having been
+perfected whilst aided by the other, must often have largely facilitated
+transitions.
+</para>
+
+<para>
+We are far too ignorant, in almost every case, to be enabled to assert that
+any part or organ is so unimportant for the welfare of a species, that
+modifications in its structure could not have been slowly accumulated by
+means of natural selection.  But we may confidently believe that many
+modifications, wholly due to the laws of growth, and at first in no way
+advantageous to a species, have been subsequently taken advantage of by the
+still further modified descendants of this species.  We may, also, believe
+that a part formerly of high importance has often been retained (as the
+tail of an aquatic animal by its terrestrial descendants), though it has
+become of such small importance that it could not, in its present state,
+have been acquired by natural selection,--a power which acts solely by the
+preservation of profitable variations in the struggle for life.
+</para>
+
+<para>
+Natural selection will produce nothing in one species for the exclusive
+good or injury of another; though it may well produce parts, organs, and
+excretions highly useful or even indispensable, or highly injurious to
+another species, but in all cases at the same time useful to the owner. 
+Natural selection in each well-stocked country, must act chiefly through
+the competition of the inhabitants one with another, and consequently will
+produce perfection, or strength in the battle for life, only according to
+the standard of that country.  Hence the inhabitants of one country,
+generally the smaller one, will often yield, as we see they do yield, to
+the inhabitants of another and generally larger country.  For in the larger
+country there will have existed more individuals, and more diversified
+forms, and the competition will have been severer, and thus the standard of
+perfection will have been rendered higher.  Natural selection will not
+necessarily produce absolute perfection; nor, as far as we can judge by our
+limited faculties, can absolute perfection be everywhere found.
+</para>
+
+<para>
+On the theory of natural selection we can clearly understand the full
+meaning of that old canon in natural history, 'Natura non facit saltum.' 
+This canon, if we look only to the present inhabitants of the world, is not
+strictly correct, but if we include all those of past times, it must by my
+theory be strictly true.
+</para>
+
+<para>
+It is generally acknowledged that all organic beings have been formed on
+two great laws--Unity of Type, and the Conditions of Existence.  By unity
+of type is meant that fundamental agreement in structure, which we see in
+organic beings of the same class, and which is quite independent of their
+habits of life.  On my theory, unity of type is explained by unity of
+descent.  The expression of conditions of existence, so often insisted on
+by the illustrious Cuvier, is fully embraced by the principle of natural
+selection.  For natural selection acts by either now adapting the varying
+parts of each being to its organic and inorganic conditions of life; or by
+having adapted them during long-past periods of time:  the adaptations
+being aided in some cases by use and disuse, being slightly affected by the
+direct action of the external conditions of life, and being in all cases
+subjected to the several laws of growth.  Hence, in fact, the law of the
+Conditions of Existence is the higher law; as it includes, through the
+inheritance of former adaptations, that of Unity of Type.
+</para>
+
+</chapter>
+
+<chapter>
+<chapheader>
+
+<chapnum>Chapter VII</chapnum>
+
+<title>Instinct</title>
+
+<chapsummary>
+Instincts comparable with habits, but different in their origin --
+Instincts graduated -- Aphides and ants -- Instincts variable -- Domestic
+instincts, their origin -- Natural instincts of the cuckoo, ostrich, and
+parasitic bees -- Slave-making ants -- Hive-bee, its cell-making instinct -
+- Difficulties on the theory of the Natural Selection of instincts --
+Neuter or sterile insects -- Summary.
+</chapsummary>
+</chapheader>
+
+<para>
+The subject of instinct might have been worked into the previous chapters;
+but I have thought that it would be more convenient to treat the subject
+separately, especially as so wonderful an instinct as that of the hive-bee
+making its cells will probably have occurred to many readers, as a
+difficulty sufficient to overthrow my whole theory.  I must premise, that I
+have nothing to do with the origin of the primary mental powers, any more
+than I have with that of life itself.  We are concerned only with the
+diversities of instinct and of the other mental qualities of animals within
+the same class.
+</para>
+
+<para>
+I will not attempt any definition of instinct.  It would be easy to show
+that several distinct mental actions are commonly embraced by this term;
+but every one understands what is meant, when it is said that instinct
+impels the cuckoo to migrate and to lay her eggs in other birds' nests.  An
+action, which we ourselves should require experience to enable us to
+perform, when performed by an animal, more especially by a very young one,
+without any experience, and when performed by many individuals in the same
+way, without their knowing for what purpose it is performed, is usually
+said to be instinctive.  But I could show that none of these characters of
+instinct are universal.  A little dose, as Pierre Huber expresses it, of
+judgment or reason, often comes into play, even in animals very low in the
+scale of nature.
+</para>
+
+<para>
+Frederick Cuvier and several of the older metaphysicians have compared
+instinct with habit.  This comparison gives, I think, a remarkably accurate
+notion of the frame of mind under which an instinctive action is performed,
+but not of its origin.  How unconsciously many habitual actions are
+performed, indeed not rarely in direct opposition to our conscious will!
+yet they may be modified by the will or reason.  Habits easily become
+associated with other habits, and with certain periods of time and states
+of the body.  When once acquired, they often remain constant throughout
+life.  Several other points of resemblance between instincts and habits
+could be pointed out.  As in repeating a well-known song, so in instincts,
+one action follows another by a sort of rhythm; if a person be interrupted
+in a song, or in repeating anything by rote, he is generally forced to go
+back to recover the habitual train of thought:  so P. Huber found it was
+with a caterpillar, which makes a very complicated hammock; for if he took
+a caterpillar which had completed its hammock up to, say, the sixth stage
+of construction, and put it into a hammock completed up only to the third
+stage, the caterpillar simply re-performed the fourth, fifth, and sixth
+stages of construction.  If, however, a caterpillar were taken out of a
+hammock made up, for instance, to the third stage, and were put into one
+finished up to the sixth stage, so that much of its work was already done
+for it, far from feeling the benefit of this, it was much embarrassed, and,
+in order to complete its hammock, seemed forced to start from the third
+stage, where it had left off, and thus tried to complete the already
+finished work.  If we suppose any habitual action to become inherited--and
+I think it can be shown that this does sometimes happen--then the
+resemblance between what originally was a habit and an instinct becomes so
+close as not to be distinguished.  If Mozart, instead of playing the
+pianoforte at three years old with wonderfully little practice, had played
+a tune with no practice at all, be might truly be said to have done so
+instinctively.  But it would be the most serious error to suppose that the
+greater number of instincts have been acquired by habit in one generation,
+and then transmitted by inheritance to succeeding generations.  It can be
+clearly shown that the most wonderful instincts with which we are
+acquainted, namely, those of the hive-bee and of many ants, could not
+possibly have been thus acquired.
+</para>
+
+<para>
+It will be universally admitted that instincts are as important as
+corporeal structure for the welfare of each species, under its present
+conditions of life.  Under changed conditions of life, it is at least
+possible that slight modifications of instinct might be profitable to a
+species; and if it can be shown that instincts do vary ever so little, then
+I can see no difficulty in natural selection preserving and continually
+accumulating variations of instinct to any extent that may be profitable. 
+It is thus, as I believe, that all the most complex and wonderful instincts
+have originated.  As modifications of corporeal structure arise from, and
+are increased by, use or habit, and are diminished or lost by disuse, so I
+do not doubt it has been with instincts.  But I believe that the effects of
+habit are of quite subordinate importance to the effects of the natural
+selection of what may be called accidental variations of instincts;--that
+is of variations produced by the same unknown causes which produce slight
+deviations of bodily structure.
+</para>
+
+<para>
+No complex instinct can possibly be produced through natural selection,
+except by the slow and gradual accumulation of numerous, slight, yet
+profitable, variations.  Hence, as in the case of corporeal structures, we
+ought to find in nature, not the actual transitional gradations by which
+each complex instinct has been acquired--for these could be found only in
+the lineal ancestors of each species--but we ought to find in the
+collateral lines of descent some evidence of such gradations; or we ought
+at least to be able to show that gradations of some kind are possible; and
+this we certainly can do.  I have been surprised to find, making allowance
+for the instincts of animals having been but little observed except in
+Europe and North America, and for no instinct being known amongst extinct
+species, how very generally gradations, leading to the most complex
+instincts, can be discovered.  The canon of 'Natura non facit saltum'
+applies with almost equal force to instincts as to bodily organs.  Changes
+of instinct may sometimes be facilitated by the same species having
+different instincts at different periods of life, or at different seasons
+of the year, or when placed under different circumstances, &amp;c.; in which
+case either one or the other instinct might be preserved by natural
+selection.  And such instances of diversity of instinct in the same species
+can be shown to occur in nature.
+</para>
+
+<para>
+Again as in the case of corporeal structure, and conformably with my
+theory, the instinct of each species is good for itself, but has never, as
+far as we can judge, been produced for the exclusive good of others.  One
+of the strongest instances of an animal apparently performing an action for
+the sole good of another, with which I am acquainted, is that of aphides
+voluntarily yielding their sweet excretion to ants:  that they do so
+voluntarily, the following facts show.  I removed all the ants from a group
+of about a dozen aphides on a dock-plant, and prevented their attendance
+during several hours.  After this interval, I felt sure that the aphides
+would want to excrete.  I watched them for some time through a lens, but
+not one excreted; I then tickled and stroked them with a hair in the same
+manner, as well as I could, as the ants do with their antennae; but not one
+excreted.  Afterwards I allowed an ant to visit them, and it immediately
+seemed, by its eager way of running about, to be well aware what a rich
+flock it had discovered; it then began to play with its antennae on the
+abdomen first of one aphis and then of another; and each aphis, as soon as
+it felt the antennae, immediately lifted up its abdomen and excreted a
+limpid drop of sweet juice, which was eagerly devoured by the ant.  Even
+the quite young aphides behaved in this manner, showing that the action was
+instinctive, and not the result of experience.  But as the excretion is
+extremely viscid, it is probably a convenience to the aphides to have it
+removed; and therefore probably the aphides do not instinctively excrete
+for the sole good of the ants.  Although I do not believe that any animal
+in the world performs an action for the exclusive good of another of a
+distinct species, yet each species tries to take advantage of the instincts
+of others, as each takes advantage of the weaker bodily structure of
+others.  So again, in some few cases, certain instincts cannot be
+considered as absolutely perfect; but as details on this and other such
+points are not indispensable, they may be here passed over.
+</para>
+
+<para>
+As some degree of variation in instincts under a state of nature, and the
+inheritance of such variations, are indispensable for the action of natural
+selection, as many instances as possible ought to have been here given; but
+want of space prevents me.  I can only assert, that instincts certainly do
+vary--for instance, the migratory instinct, both in extent and direction,
+and in its total loss.  So it is with the nests of birds, which vary partly
+in dependence on the situations chosen, and on the nature and temperature
+of the country inhabited, but often from causes wholly unknown to us: 
+Audubon has given several remarkable cases of differences in nests of the
+same species in the northern and southern United States.  Fear of any
+particular enemy is certainly an instinctive quality, as may be seen in
+nestling birds, though it is strengthened by experience, and by the sight
+of fear of the same enemy in other animals.  But fear of man is slowly
+acquired, as I have elsewhere shown, by various animals inhabiting desert
+islands; and we may see an instance of this, even in England, in the
+greater wildness of all our large birds than of our small birds; for the
+large birds have been most persecuted by man.  We may safely attribute the
+greater wildness of our large birds to this cause; for in uninhabited
+islands large birds are not more fearful than small; and the magpie, so
+wary in England, is tame in Norway, as is the hooded crow in Egypt.
+</para>
+
+<para>
+That the general disposition of individuals of the same species, born in a
+state of nature, is extremely diversified, can be shown by a multitude of
+facts.  Several cases also, could be given, of occasional and strange
+habits in certain species, which might, if advantageous to the species,
+give rise, through natural selection, to quite new instincts.  But I am
+well aware that these general statements, without facts given in detail,
+can produce but a feeble effect on the reader's mind.  I can only repeat my
+assurance, that I do not speak without good evidence.
+</para>
+
+<para>
+The possibility, or even probability, of inherited variations of instinct
+in a state of nature will be strengthened by briefly considering a few
+cases under domestication.  We shall thus also be enabled to see the
+respective parts which habit and the selection of so-called accidental
+variations have played in modifying the mental qualities of our domestic
+animals.  A number of curious and authentic instances could be given of the
+inheritance of all shades of disposition and tastes, and likewise of the
+oddest tricks, associated with certain frames of mind or periods of time. 
+But let us look to the familiar case of the several breeds of dogs:  it
+cannot be doubted that young pointers (I have myself seen a striking
+instance) will sometimes point and even back other dogs the very first time
+that they are taken out; retrieving is certainly in some degree inherited
+by retrievers; and a tendency to run round, instead of at, a flock of
+sheep, by shepherd-dogs.  I cannot see that these actions, performed
+without experience by the young, and in nearly the same manner by each
+individual, performed with eager delight by each breed, and without the end
+being known,--for the young pointer can no more know that he points to aid
+his master, than the white butterfly knows why she lays her eggs on the
+leaf of the cabbage,--I cannot see that these actions differ essentially
+from true instincts.  If we were to see one kind of wolf, when young and
+without any training, as soon as it scented its prey, stand motionless like
+a statue, and then slowly crawl forward with a peculiar gait; and another
+kind of wolf rushing round, instead of at, a herd of deer, and driving them
+to a distant point, we should assuredly call these actions instinctive. 
+Domestic instincts, as they may be called, are certainly far less fixed or
+invariable than natural instincts; but they have been acted on by far less
+rigorous selection, and have been transmitted for an incomparably shorter
+period, under less fixed conditions of life.
+</para>
+
+<para>
+How strongly these domestic instincts, habits, and dispositions are
+inherited, and how curiously they become mingled, is well shown when
+different breeds of dogs are crossed.  Thus it is known that a cross with a
+bull-dog has affected for many generations the courage and obstinacy of
+greyhounds; and a cross with a greyhound has given to a whole family of
+shepherd-dogs a tendency to hunt hares.  These domestic instincts, when
+thus tested by crossing, resemble natural instincts, which in a like manner
+become curiously blended together, and for a long period exhibit traces of
+the instincts of either parent:  for example, Le Roy describes a dog, whose
+great-grandfather was a wolf, and this dog showed a trace of its wild
+parentage only in one way, by not coming in a straight line to his master
+when called.
+</para>
+
+<para>
+Domestic instincts are sometimes spoken of as actions which have become
+inherited solely from long-continued and compulsory habit, but this, I
+think, is not true.  No one would ever have thought of teaching, or
+probably could have taught, the tumbler-pigeon to tumble,--an action which,
+as I have witnessed, is performed by young birds, that have never seen a
+pigeon tumble.  We may believe that some one pigeon showed a slight
+tendency to this strange habit, and that the long-continued selection of
+the best individuals in successive generations made tumblers what they now
+are; and near Glasgow there are house-tumblers, as I hear from Mr. Brent,
+which cannot fly eighteen inches high without going head over heels.  It
+may be doubted whether any one would have thought of training a dog to
+point, had not some one dog naturally shown a tendency in this line; and
+this is known occasionally to happen, as I once saw in a pure terrier. 
+When the first tendency was once displayed, methodical selection and the
+inherited effects of compulsory training in each successive generation
+would soon complete the work; and unconscious selection is still at work,
+as each man tries to procure, without intending to improve the breed, dogs
+which will stand and hunt best.  On the other hand, habit alone in some
+cases has sufficed; no animal is more difficult to tame than the young of
+the wild rabbit; scarcely any animal is tamer than the young of the tame
+rabbit; but I do not suppose that domestic rabbits have ever been selected
+for tameness; and I presume that we must attribute the whole of the
+inherited change from extreme wildness to extreme tameness, simply to habit
+and long-continued close confinement.
+</para>
+
+<para>
+Natural instincts are lost under domestication:  a remarkable instance of
+this is seen in those breeds of fowls which very rarely or never become
+'broody,' that is, never wish to sit on their eggs.  Familiarity alone
+prevents our seeing how universally and largely the minds of our domestic
+animals have been modified by domestication.  It is scarcely possible to
+doubt that the love of man has become instinctive in the dog.  All wolves,
+foxes, jackals, and species of the cat genus, when kept tame, are most
+eager to attack poultry, sheep, and pigs; and this tendency has been found
+incurable in dogs which have been brought home as puppies from countries,
+such as Tierra del Fuego and Australia, where the savages do not keep these
+domestic animals.  How rarely, on the other hand, do our civilised dogs,
+even when quite young, require to be taught not to attack poultry, sheep,
+and pigs!  No doubt they occasionally do make an attack, and are then
+beaten; and if not cured, they are destroyed; so that habit, with some
+degree of selection, has probably concurred in civilising by inheritance
+our dogs.  On the other hand, young chickens have lost, wholly by habit,
+that fear of the dog and cat which no doubt was originally instinctive in
+them, in the same way as it is so plainly instinctive in young pheasants,
+though reared under a hen.  It is not that chickens have lost all fear, but
+fear only of dogs and cats, for if the hen gives the danger-chuckle, they
+will run (more especially young turkeys) from under her, and conceal
+themselves in the surrounding grass or thickets; and this is evidently done
+for the instinctive purpose of allowing, as we see in wild ground-birds,
+their mother to fly away.  But this instinct retained by our chickens has
+become useless under domestication, for the mother-hen has almost lost by
+disuse the power of flight.
+</para>
+
+<para>
+Hence, we may conclude, that domestic instincts have been acquired and
+natural instincts have been lost partly by habit, and partly by man
+selecting and accumulating during successive generations, peculiar mental
+habits and actions, which at first appeared from what we must in our
+ignorance call an accident.  In some cases compulsory habit alone has
+sufficed to produce such inherited mental changes; in other cases
+compulsory habit has done nothing, and all has been the result of
+selection, pursued both methodically and unconsciously; but in most cases,
+probably, habit and selection have acted together.
+</para>
+
+<para>
+We shall, perhaps, best understand how instincts in a state of nature have
+become modified by selection, by considering a few cases.  I will select
+only three, out of the several which I shall have to discuss in my future
+work,--namely, the instinct which leads the cuckoo to lay her eggs in other
+birds' nests; the slave-making instinct of certain ants; and the
+comb-making power of the hive-bee:  these two latter instincts have
+generally, and most justly, been ranked by naturalists as the most
+wonderful of all known instincts.
+</para>
+
+<para>
+It is now commonly admitted that the more immediate and final cause of the
+cuckoo's instinct is, that she lays her eggs, not daily, but at intervals
+of two or three days; so that, if she were to make her own nest and sit on
+her own eggs, those first laid would have to be left for some time
+unincubated, or there would be eggs and young birds of different ages in
+the same nest.  If this were the case, the process of laying and hatching
+might be inconveniently long, more especially as she has to migrate at a
+very early period; and the first hatched young would probably have to be
+fed by the male alone.  But the American cuckoo is in this predicament; for
+she makes her own nest and has eggs and young successively hatched, all at
+the same time.  It has been asserted that the American cuckoo occasionally
+lays her eggs in other birds' nests; but I hear on the high authority of
+Dr. Brewer, that this is a mistake.  Nevertheless, I could give several
+instances of various birds which have been known occasionally to lay their
+eggs in other birds' nests.  Now let us suppose that the ancient progenitor
+of our European cuckoo had the habits of the American cuckoo; but that
+occasionally she laid an egg in another bird's nest.  If the old bird
+profited by this occasional habit, or if the young were made more vigorous
+by advantage having been taken of the mistaken maternal instinct of another
+bird, than by their own mother's care, encumbered as she can hardly fail to
+be by having eggs and young of different ages at the same time; then the
+old birds or the fostered young would gain an advantage.  And analogy would
+lead me to believe, that the young thus reared would be apt to follow by
+inheritance the occasional and aberrant habit of their mother, and in their
+turn would be apt to lay their eggs in other birds' nests, and thus be
+successful in rearing their young.  By a continued process of this nature,
+I believe that the strange instinct of our cuckoo could be, and has been,
+generated.  I may add that, according to Dr. Gray and to some other
+observers, the European cuckoo has not utterly lost all maternal love and
+care for her own offspring.
+</para>
+
+<para>
+The occasional habit of birds laying their eggs in other birds' nests,
+either of the same or of a distinct species, is not very uncommon with the
+Gallinaceae; and this perhaps explains the origin of a singular instinct in
+the allied group of ostriches.  For several hen ostriches, at least in the
+case of the American species, unite and lay first a few eggs in one nest
+and then in another; and these are hatched by the males.  This instinct may
+probably be accounted for by the fact of the hens laying a large number of
+eggs; but, as in the case of the cuckoo, at intervals of two or three days. 
+This instinct, however, of the American ostrich has not as yet been
+perfected; for a surprising number of eggs lie strewed over the plains, so
+that in one day's hunting I picked up no less than twenty lost and wasted
+eggs.
+</para>
+
+<para>
+Many bees are parasitic, and always lay their eggs in the nests of bees of
+other kinds.  This case is more remarkable than that of the cuckoo; for
+these bees have not only their instincts but their structure modified in
+accordance with their parasitic habits; for they do not possess the
+pollen-collecting apparatus which would be necessary if they had to store
+food for their own young.  Some species, likewise, of Sphegidae (wasp-like
+insects) are parasitic on other species; and M. Fabre has lately shown good
+reason for believing that although the Tachytes nigra generally makes its
+own burrow and stores it with paralysed prey for its own larvae to feed on,
+yet that when this insect finds a burrow already made and stored by another
+sphex, it takes advantage of the prize, and becomes for the occasion
+parasitic.  In this case, as with the supposed case of the cuckoo, I can
+see no difficulty in natural selection making an occasional habit
+permanent, if of advantage to the species, and if the insect whose nest and
+stored food are thus feloniously appropriated, be not thus exterminated.
+</para>
+
+<para>
+Slave-making instinct. -- This remarkable instinct was first discovered in
+the Formica (Polyerges) rufescens by Pierre Huber, a better observer even
+than his celebrated father.  This ant is absolutely dependent on its
+slaves; without their aid, the species would certainly become extinct in a
+single year.  The males and fertile females do no work.  The workers or
+sterile females, though most energetic and courageous in capturing slaves,
+do no other work.  They are incapable of making their own nests, or of
+feeding their own larvae.  When the old nest is found inconvenient, and
+they have to migrate, it is the slaves which determine the migration, and
+actually carry their masters in their jaws.  So utterly helpless are the
+masters, that when Huber shut up thirty of them without a slave, but with
+plenty of the food which they like best, and with their larvae and pupae to
+stimulate them to work, they did nothing; they could not even feed
+themselves, and many perished of hunger.  Huber then introduced a single
+slave (F. fusca), and she instantly set to work, fed and saved the
+survivors; made some cells and tended the larvae, and put all to rights. 
+What can be more extraordinary than these well-ascertained facts?  If we
+had not known of any other slave-making ant, it would have been hopeless to
+have speculated how so wonderful an instinct could have been perfected.
+</para>
+
+<para>
+Formica sanguinea was likewise first discovered by P. Huber to be a
+slave-making ant.  This species is found in the southern parts of England,
+and its habits have been attended to by Mr. F. Smith, of the British
+Museum, to whom I am much indebted for information on this and other
+subjects.  Although fully trusting to the statements of Huber and Mr.
+Smith, I tried to approach the subject in a sceptical frame of mind, as any
+one may well be excused for doubting the truth of so extraordinary and
+odious an instinct as that of making slaves.  Hence I will give the
+observations which I have myself made, in some little detail.  I opened
+fourteen nests of F. sanguinea, and found a few slaves in all.  Males and
+fertile females of the slave-species are found only in their own proper
+communities, and have never been observed in the nests of F. sanguinea. 
+The slaves are black and not above half the size of their red masters, so
+that the contrast in their appearance is very great.  When the nest is
+slightly disturbed, the slaves occasionally come out, and like their
+masters are much agitated and defend their nest:  when the nest is much
+disturbed and the larvae and pupae are exposed, the slaves work
+energetically with their masters in carrying them away to a place of
+safety.  Hence, it is clear, that the slaves feel quite at home.  During
+the months of June and July, on three successive years, I have watched for
+many hours several nests in Surrey and Sussex, and never saw a slave either
+leave or enter a nest.  As, during these months, the slaves are very few in
+number, I thought that they might behave differently when more numerous;
+but Mr. Smith informs me that he has watched the nests at various hours
+during May, June and August, both in Surrey and Hampshire, and has never
+seen the slaves, though present in large numbers in August, either leave or
+enter the nest.  Hence he considers them as strictly household slaves.  The
+masters, on the other hand, may be constantly seen bringing in materials
+for the nest, and food of all kinds.  During the present year, however, in
+the month of July, I came across a community with an unusually large stock
+of slaves, and I observed a few slaves mingled with their masters leaving
+the nest, and marching along the same road to a tall Scotch-fir-tree,
+twenty-five yards distant, which they ascended together, probably in search
+of aphides or cocci.  According to Huber, who had ample opportunities for
+observation, in Switzerland the slaves habitually work with their masters
+in making the nest, and they alone open and close the doors in the morning
+and evening; and, as Huber expressly states, their principal office is to
+search for aphides.  This difference in the usual habits of the masters and
+slaves in the two countries, probably depends merely on the slaves being
+captured in greater numbers in Switzerland than in England.
+</para>
+
+<para>
+One day I fortunately chanced to witness a migration from one nest to
+another, and it was a most interesting spectacle to behold the masters
+carefully carrying, as Huber has described, their slaves in their jaws. 
+Another day my attention was struck by about a score of the slave-makers
+haunting the same spot, and evidently not in search of food; they
+approached and were vigorously repulsed by an independent community of the
+slave species (F. fusca); sometimes as many as three of these ants clinging
+to the legs of the slave-making F. sanguinea.  The latter ruthlessly killed
+their small opponents, and carried their dead bodies as food to their nest,
+twenty-nine yards distant; but they were prevented from getting any pupae
+to rear as slaves.  I then dug up a small parcel of the pupae of F. fusca
+from another nest, and put them down on a bare spot near the place of
+combat; they were eagerly seized, and carried off by the tyrants, who
+perhaps fancied that, after all, they had been victorious in their late
+combat.
+</para>
+
+<para>
+At the same time I laid on the same place a small parcel of the pupae of
+another species, F. flava, with a few of these little yellow ants still
+clinging to the fragments of the nest.  This species is sometimes, though
+rarely, made into slaves, as has been described by Mr. Smith.  Although so
+small a species, it is very courageous, and I have seen it ferociously
+attack other ants.  In one instance I found to my surprise an independent
+community of F. flava under a stone beneath a nest of the slave-making F.
+sanguinea; and when I had accidentally disturbed both nests, the little
+ants attacked their big neighbours with surprising courage.  Now I was
+curious to ascertain whether F. sanguinea could distinguish the pupae of F.
+fusca, which they habitually make into slaves, from those of the little and
+furious F. flava, which they rarely capture, and it was evident that they
+did at once distinguish them:  for we have seen that they eagerly and
+instantly seized the pupae of F. fusca, whereas they were much terrified
+when they came across the pupae, or even the earth from the nest of F.
+flava, and quickly ran away; but in about a quarter of an hour, shortly
+after all the little yellow ants had crawled away, they took heart and
+carried off the pupae.
+</para>
+
+<para>
+One evening I visited another community of F. sanguinea, and found a number
+of these ants entering their nest, carrying the dead bodies of F. fusca
+(showing that it was not a migration) and numerous pupae.  I traced the
+returning file burthened with booty, for about forty yards, to a very thick
+clump of heath, whence I saw the last individual of F. sanguinea emerge,
+carrying a pupa; but I was not able to find the desolated nest in the thick
+heath.  The nest, however, must have been close at hand, for two or three
+individuals of F. fusca were rushing about in the greatest agitation, and
+one was perched motionless with its own pupa in its mouth on the top of a
+spray of heath over its ravaged home.
+</para>
+
+<para>
+Such are the facts, though they did not need confirmation by me, in regard
+to the wonderful instinct of making slaves.  Let it be observed what a
+contrast the instinctive habits of F. sanguinea present with those of the
+F. rufescens.  The latter does not build its own nest, does not determine
+its own migrations, does not collect food for itself or its young, and
+cannot even feed itself:  it is absolutely dependent on its numerous
+slaves.  Formica sanguinea, on the other hand, possesses much fewer slaves,
+and in the early part of the summer extremely few.  The masters determine
+when and where a new nest shall be formed, and when they migrate, the
+masters carry the slaves.  Both in Switzerland and England the slaves seem
+to have the exclusive care of the larvae, and the masters alone go on
+slave-making expeditions.  In Switzerland the slaves and masters work
+together, making and bringing materials for the nest:  both, but chiefly
+the slaves, tend, and milk as it may be called, their aphides; and thus
+both collect food for the community.  In England the masters alone usually
+leave the nest to collect building materials and food for themselves, their
+slaves and larvae.  So that the masters in this country receive much less
+service from their slaves than they do in Switzerland.
+</para>
+
+<para>
+By what steps the instinct of F. sanguinea originated I will not pretend to
+conjecture.  But as ants, which are not slave-makers, will, as I have seen,
+carry off pupae of other species, if scattered near their nests, it is
+possible that pupae originally stored as food might become developed; and
+the ants thus unintentionally reared would then follow their proper
+instincts, and do what work they could.  If their presence proved useful to
+the species which had seized them--if it were more advantageous to this
+species to capture workers than to procreate them--the habit of collecting
+pupae originally for food might by natural selection be strengthened and
+rendered permanent for the very different purpose of raising slaves.  When
+the instinct was once acquired, if carried out to a much less extent even
+than in our British F. sanguinea, which, as we have seen, is less aided by
+its slaves than the same species in Switzerland, I can see no difficulty in
+natural selection increasing and modifying the instinct--always supposing
+each modification to be of use to the species--until an ant was formed as
+abjectly dependent on its slaves as is the Formica rufescens.
+</para>
+
+<para>
+Cell-making instinct of the Hive-Bee. -- I will not here enter on minute
+details on this subject, but will merely give an outline of the conclusions
+at which I have arrived.  He must be a dull man who can examine the
+exquisite structure of a comb, so beautifully adapted to its end, without
+enthusiastic admiration.  We hear from mathematicians that bees have
+practically solved a recondite problem, and have made their cells of the
+proper shape to hold the greatest possible amount of honey, with the least
+possible consumption of precious wax in their construction.  It has been
+remarked that a skilful workman, with fitting tools and measures, would
+find it very difficult to make cells of wax of the true form, though this
+is perfectly effected by a crowd of bees working in a dark hive.  Grant
+whatever instincts you please, and it seems at first quite inconceivable
+how they can make all the necessary angles and planes, or even perceive
+when they are correctly made.  But the difficulty is not nearly so great as
+it at first appears:  all this beautiful work can be shown, I think, to
+follow from a few very simple instincts.
+</para>
+
+<para>
+I was led to investigate this subject by Mr. Waterhouse, who has shown that
+the form of the cell stands in close relation to the presence of adjoining
+cells; and the following view may, perhaps, be considered only as a
+modification of this theory.  Let us look to the great principle of
+gradation, and see whether Nature does not reveal to us her method of work. 
+At one end of a short series we have humble-bees, which use their old
+cocoons to hold honey, sometimes adding to them short tubes of wax, and
+likewise making separate and very irregular rounded cells of wax.  At the
+other end of the series we have the cells of the hive-bee, placed in a
+double layer:  each cell, as is well known, is an hexagonal prism, with the
+basal edges of its six sides bevelled so as to join on to a pyramid, formed
+of three rhombs.  These rhombs have certain angles, and the three which
+form the pyramidal base of a single cell on one side of the comb, enter
+into the composition of the bases of three adjoining cells on the opposite
+side.  In the series between the extreme perfection of the cells of the
+hive-bee and the simplicity of those of the humble-bee, we have the cells
+of the Mexican Melipona domestica, carefully described and figured by
+Pierre Huber.  The Melipona itself is intermediate in structure between the
+hive and humble bee, but more nearly related to the latter:  it forms a
+nearly regular waxen comb of cylindrical cells, in which the young are
+hatched, and, in addition, some large cells of wax for holding honey. 
+These latter cells are nearly spherical and of nearly equal sizes, and are
+aggregated into an irregular mass.  But the important point to notice, is
+that these cells are always made at that degree of nearness to each other,
+that they would have intersected or broken into each other, if the spheres
+had been completed; but this is never permitted, the bees building
+perfectly flat walls of wax between the spheres which thus tend to
+intersect.  Hence each cell consists of an outer spherical portion and of
+two, three, or more perfectly flat surfaces, according as the cell adjoins
+two, three or more other cells.  When one cell comes into contact with
+three other cells, which, from the spheres being nearly of the same size,
+is very frequently and necessarily the case, the three flat surfaces are
+united into a pyramid; and this pyramid, as Huber has remarked, is
+manifestly a gross imitation of the three-sided pyramidal basis of the cell
+of the hive-bee.  As in the cells of the hive-bee, so here, the three plane
+surfaces in any one cell necessarily enter into the construction of three
+adjoining cells.  It is obvious that the Melipona saves wax by this manner
+of building; for the flat walls between the adjoining cells are not double,
+but are of the same thickness as the outer spherical portions, and yet each
+flat portion forms a part of two cells.
+</para>
+
+<para>
+Reflecting on this case, it occurred to me that if the Melipona had made
+its spheres at some given distance from each other, and had made them of
+equal sizes and had arranged them symmetrically in a double layer, the
+resulting structure would probably have been as perfect as the comb of the
+hive-bee.  Accordingly I wrote to Professor Miller, of Cambridge, and this
+geometer has kindly read over the following statement, drawn up from his
+information, and tells me that it is strictly correct:-
+</para>
+
+<para>
+If a number of equal spheres be described with their centres placed in two
+parallel layers; with the centre of each sphere at the distance of radius x
+sqrt(2) or radius x 1.41421 (or at some lesser distance), from the centres
+of the six surrounding spheres in the same layer; and at the same distance
+from the centres of the adjoining spheres in the other and parallel layer;
+then, if planes of intersection between the several spheres in both layers
+be formed, there will result a double layer of hexagonal prisms united
+together by pyramidal bases formed of three rhombs; and the rhombs and the
+sides of the hexagonal prisms will have every angle identically the same
+with the best measurements which have been made of the cells of the
+hive-bee.
+</para>
+
+<para>
+Hence we may safely conclude that if we could slightly modify the instincts
+already possessed by the Melipona, and in themselves not very wonderful,
+this bee would make a structure as wonderfully perfect as that of the
+hive-bee.  We must suppose the Melipona to make her cells truly spherical,
+and of equal sizes; and this would not be very surprising, seeing that she
+already does so to a certain extent, and seeing what perfectly cylindrical
+burrows in wood many insects can make, apparently by turning round on a
+fixed point.  We must suppose the Melipona to arrange her cells in level
+layers, as she already does her cylindrical cells; and we must further
+suppose, and this is the greatest difficulty, that she can somehow judge
+accurately at what distance to stand from her fellow-labourers when several
+are making their spheres; but she is already so far enabled to judge of
+distance, that she always describes her spheres so as to intersect largely;
+and then she unites the points of intersection by perfectly flat surfaces. 
+We have further to suppose, but this is no difficulty, that after hexagonal
+prisms have been formed by the intersection of adjoining spheres in the
+same layer, she can prolong the hexagon to any length requisite to hold the
+stock of honey; in the same way as the rude humble-bee adds cylinders of
+wax to the circular mouths of her old cocoons.  By such modifications of
+instincts in themselves not very wonderful,--hardly more wonderful than
+those which guide a bird to make its nest,--I believe that the hive-bee has
+acquired, through natural selection, her inimitable architectural powers.
+</para>
+
+<para>
+But this theory can be tested by experiment.  Following the example of Mr.
+Tegetmeier, I separated two combs, and put between them a long, thick,
+square strip of wax:  the bees instantly began to excavate minute circular
+pits in it; and as they deepened these little pits, they made them wider
+and wider until they were converted into shallow basins, appearing to the
+eye perfectly true or parts of a sphere, and of about the diameter of a
+cell.  It was most interesting to me to observe that wherever several bees
+had begun to excavate these basins near together, they had begun their work
+at such a distance from each other, that by the time the basins had
+acquired the above stated width (i.e. about the width of an ordinary cell),
+and were in depth about one sixth of the diameter of the sphere of which
+they formed a part, the rims of the basins intersected or broke into each
+other.  As soon as this occurred, the bees ceased to excavate, and began to
+build up flat walls of wax on the lines of intersection between the basins,
+so that each hexagonal prism was built upon the festooned edge of a smooth
+basin, instead of on the straight edges of a three-sided pyramid as in the
+case of ordinary cells.
+</para>
+
+<para>
+I then put into the hive, instead of a thick, square piece of wax, a thin
+and narrow, knife-edged ridge, coloured with vermilion.  The bees instantly
+began on both sides to excavate little basins near to each other, in the
+same way as before; but the ridge of wax was so thin, that the bottoms of
+the basins, if they had been excavated to the same depth as in the former
+experiment, would have broken into each other from the opposite sides.  The
+bees, however, did not suffer this to happen, and they stopped their
+excavations in due time; so that the basins, as soon as they had been a
+little deepened, came to have flat bottoms; and these flat bottoms, formed
+by thin little plates of the vermilion wax having been left ungnawed, were
+situated, as far as the eye could judge, exactly along the planes of
+imaginary intersection between the basins on the opposite sides of the
+ridge of wax.  In parts, only little bits, in other parts, large portions
+of a rhombic plate had been left between the opposed basins, but the work,
+from the unnatural state of things, had not been neatly performed.  The
+bees must have worked at very nearly the same rate on the opposite sides of
+the ridge of vermilion wax, as they circularly gnawed away and deepened the
+basins on both sides, in order to have succeeded in thus leaving flat
+plates between the basins, by stopping work along the intermediate planes
+or planes of intersection.
+</para>
+
+<para>
+Considering how flexible thin wax is, I do not see that there is any
+difficulty in the bees, whilst at work on the two sides of a strip of wax,
+perceiving when they have gnawed the wax away to the proper thinness, and
+then stopping their work.  In ordinary combs it has appeared to me that the
+bees do not always succeed in working at exactly the same rate from the
+opposite sides; for I have noticed half-completed rhombs at the base of a
+just-commenced cell, which were slightly concave on one side, where I
+suppose that the bees had excavated too quickly, and convex on the opposed
+side, where the bees had worked less quickly.  In one well-marked instance,
+I put the comb back into the hive, and allowed the bees to go on working
+for a short time, and again examined the cell, and I found that the rhombic
+plate had been completed, and had become perfectly flat:  it was absolutely
+impossible, from the extreme thinness of the little rhombic plate, that
+they could have effected this by gnawing away the convex side; and I
+suspect that the bees in such cases stand in the opposed cells and push and
+bend the ductile and warm wax (which as I have tried is easily done) into
+its proper intermediate plane, and thus flatten it.
+</para>
+
+<para>
+From the experiment of the ridge of vermilion wax, we can clearly see that
+if the bees were to build for themselves a thin wall of wax, they could
+make their cells of the proper shape, by standing at the proper distance
+from each other, by excavating at the same rate, and by endeavouring to
+make equal spherical hollows, but never allowing the spheres to break into
+each other.  Now bees, as may be clearly seen by examining the edge of a
+growing comb, do make a rough, circumferential wall or rim all round the
+comb; and they gnaw into this from the opposite sides, always working
+circularly as they deepen each cell.  They do not make the whole
+three-sided pyramidal base of any one cell at the same time, but only the
+one rhombic plate which stands on the extreme growing margin, or the two
+plates, as the case may be; and they never complete the upper edges of the
+rhombic plates, until the hexagonal walls are commenced.  Some of these
+statements differ from those made by the justly celebrated elder Huber, but
+I am convinced of their accuracy; and if I had space, I could show that
+they are conformable with my theory.
+</para>
+
+<para>
+Huber's statement that the very first cell is excavated out of a little
+parallel-sided wall of wax, is not, as far as I have seen, strictly
+correct; the first commencement having always been a little hood of wax;
+but I will not here enter on these details.  We see how important a part
+excavation plays in the construction of the cells; but it would be a great
+error to suppose that the bees cannot build up a rough wall of wax in the
+proper position--that is, along the plane of intersection between two
+adjoining spheres.  I have several specimens showing clearly that they can
+do this.  Even in the rude circumferential rim or wall of wax round a
+growing comb, flexures may sometimes be observed, corresponding in position
+to the planes of the rhombic basal plates of future cells.  But the rough
+wall of wax has in every case to be finished off, by being largely gnawed
+away on both sides.  The manner in which the bees build is curious; they
+always make the first rough wall from ten to twenty times thicker than the
+excessively thin finished wall of the cell, which will ultimately be left. 
+We shall understand how they work, by supposing masons first to pile up a
+broad ridge of cement, and then to begin cutting it away equally on both
+sides near the ground, till a smooth, very thin wall is left in the middle;
+the masons always piling up the cut-away cement, and adding fresh cement,
+on the summit of the ridge.  We shall thus have a thin wall steadily
+growing upward; but always crowned by a gigantic coping.  From all the
+cells, both those just commenced and those completed, being thus crowned by
+a strong coping of wax, the bees can cluster and crawl over the comb
+without injuring the delicate hexagonal walls, which are only about one
+four-hundredth of an inch in thickness; the plates of the pyramidal basis
+being about twice as thick.  By this singular manner of building, strength
+is continually given to the comb, with the utmost ultimate economy of wax.
+</para>
+
+<para>
+It seems at first to add to the difficulty of understanding how the cells
+are made, that a multitude of bees all work together; one bee after working
+a short time at one cell going to another, so that, as Huber has stated, a
+score of individuals work even at the commencement of the first cell.  I
+was able practically to show this fact, by covering the edges of the
+hexagonal walls of a single cell, or the extreme margin of the
+circumferential rim of a growing comb, with an extremely thin layer of
+melted vermilion wax; and I invariably found that the colour was most
+delicately diffused by the bees--as delicately as a painter could have done
+with his brush--by atoms of the coloured wax having been taken from the
+spot on which it had been placed, and worked into the growing edges of the
+cells all round.  The work of construction seems to be a sort of balance
+struck between many bees, all instinctively standing at the same relative
+distance from each other, all trying to sweep equal spheres, and then
+building up, or leaving ungnawed, the planes of intersection between these
+spheres.  It was really curious to note in cases of difficulty, as when two
+pieces of comb met at an angle, how often the bees would entirely pull down
+and rebuild in different ways the same cell, sometimes recurring to a shape
+which they had at first rejected.
+</para>
+
+<para>
+When bees have a place on which they can stand in their proper positions
+for working,--for instance, on a slip of wood, placed directly under the
+middle of a comb growing downwards so that the comb has to be built over
+one face of the slip--in this case the bees can lay the foundations of one
+wall of a new hexagon, in its strictly proper place, projecting beyond the
+other completed cells.  It suffices that the bees should be enabled to
+stand at their proper relative distances from each other and from the walls
+of the last completed cells, and then, by striking imaginary spheres, they
+can build up a wall intermediate between two adjoining spheres; but, as far
+as I have seen, they never gnaw away and finish off the angles of a cell
+till a large part both of that cell and of the adjoining cells has been
+built.  This capacity in bees of laying down under certain circumstances a
+rough wall in its proper place between two just-commenced cells, is
+important, as it bears on a fact, which seems at first quite subversive of
+the foregoing theory; namely, that the cells on the extreme margin of
+wasp-combs are sometimes strictly hexagonal; but I have not space here to
+enter on this subject.  Nor does there seem to me any great difficulty in a
+single insect (as in the case of a queen-wasp) making hexagonal cells, if
+she work alternately on the inside and outside of two or three cells
+commenced at the same time, always standing at the proper relative distance
+from the parts of the cells just begun, sweeping spheres or cylinders, and
+building up intermediate planes.  It is even conceivable that an insect
+might, by fixing on a point at which to commence a cell, and then moving
+outside, first to one point, and then to five other points, at the proper
+relative distances from the central point and from each other, strike the
+planes of intersection, and so make an isolated hexagon:  but I am not
+aware that any such case has been observed; nor would any good be derived
+from a single hexagon being built, as in its construction more materials
+would be required than for a cylinder.
+</para>
+
+<para>
+As natural selection acts only by the accumulation of slight modifications
+of structure or instinct, each profitable to the individual under its
+conditions of life, it may reasonably be asked, how a long and graduated
+succession of modified architectural instincts, all tending towards the
+present perfect plan of construction, could have profited the progenitors
+of the hive-bee?  I think the answer is not difficult:  it is known that
+bees are often hard pressed to get sufficient nectar; and I am informed by
+Mr. Tegetmeier that it has been experimentally found that no less than from
+twelve to fifteen pounds of dry sugar are consumed by a hive of bees for
+the secretion of each pound of wax; so that a prodigious quantity of fluid
+nectar must be collected and consumed by the bees in a hive for the
+secretion of the wax necessary for the construction of their combs. 
+Moreover, many bees have to remain idle for many days during the process of
+secretion.  A large store of honey is indispensable to support a large
+stock of bees during the winter; and the security of the hive is known
+mainly to depend on a large number of bees being supported.  Hence the
+saving of wax by largely saving honey must be a most important element of
+success in any family of bees.  Of course the success of any species of bee
+may be dependent on the number of its parasites or other enemies, or on
+quite distinct causes, and so be altogether independent of the quantity of
+honey which the bees could collect.  But let us suppose that this latter
+circumstance determined, as it probably often does determine, the numbers
+of a humble-bee which could exist in a country; and let us further suppose
+that the community lived throughout the winter, and consequently required a
+store of honey:  there can in this case be no doubt that it would be an
+advantage to our humble-bee, if a slight modification of her instinct led
+her to make her waxen cells near together, so as to intersect a little; for
+a wall in common even to two adjoining cells, would save some little wax. 
+Hence it would continually be more and more advantageous to our humble-bee,
+if she were to make her cells more and more regular, nearer together, and
+aggregated into a mass, like the cells of the Melipona; for in this case a
+large part of the bounding surface of each cell would serve to bound other
+cells, and much wax would be saved.  Again, from the same cause, it would
+be advantageous to the Melipona, if she were to make her cells closer
+together, and more regular in every way than at present; for then, as we
+have seen, the spherical surfaces would wholly disappear, and would all be
+replaced by plane surfaces; and the Melipona would make a comb as perfect
+as that of the hive-bee.  Beyond this stage of perfection in architecture,
+natural selection could not lead; for the comb of the hive-bee, as far as
+we can see, is absolutely perfect in economising wax.
+</para>
+
+<para>
+Thus, as I believe, the most wonderful of all known instincts, that of the
+hive-bee, can be explained by natural selection having taken advantage of
+numerous, successive, slight modifications of simpler instincts; natural
+selection having by slow degrees, more and more perfectly, led the bees to
+sweep equal spheres at a given distance from each other in a double layer,
+and to build up and excavate the wax along the planes of intersection.  The
+bees, of course, no more knowing that they swept their spheres at one
+particular distance from each other, than they know what are the several
+angles of the hexagonal prisms and of the basal rhombic plates.  The motive
+power of the process of natural selection having been economy of wax; that
+individual swarm which wasted least honey in the secretion of wax, having
+succeeded best, and having transmitted by inheritance its newly acquired
+economical instinct to new swarms, which in their turn will have had the
+best chance of succeeding in the struggle for existence.
+</para>
+
+<para>
+No doubt many instincts of very difficult explanation could be opposed to
+the theory of natural selection,--cases, in which we cannot see how an
+instinct could possibly have originated; cases, in which no intermediate
+gradations are known to exist; cases of instinct of apparently such
+trifling importance, that they could hardly have been acted on by natural
+selection; cases of instincts almost identically the same in animals so
+remote in the scale of nature, that we cannot account for their similarity
+by inheritance from a common parent, and must therefore believe that they
+have been acquired by independent acts of natural selection.  I will not
+here enter on these several cases, but will confine myself to one special
+difficulty, which at first appeared to me insuperable, and actually fatal
+to my whole theory.  I allude to the neuters or sterile females in
+insect-communities:  for these neuters often differ widely in instinct and
+in structure from both the males and fertile females, and yet, from being
+sterile, they cannot propagate their kind.
+</para>
+
+<para>
+The subject well deserves to be discussed at great length, but I will here
+take only a single case, that of working or sterile ants.  How the workers
+have been rendered sterile is a difficulty; but not much greater than that
+of any other striking modification of structure; for it can be shown that
+some insects and other articulate animals in a state of nature occasionally
+become sterile; and if such insects had been social, and it had been
+profitable to the community that a number should have been annually born
+capable of work, but incapable of procreation, I can see no very great
+difficulty in this being effected by natural selection.  But I must pass
+over this preliminary difficulty.  The great difficulty lies in the working
+ants differing widely from both the males and the fertile females in
+structure, as in the shape of the thorax and in being destitute of wings
+and sometimes of eyes, and in instinct.  As far as instinct alone is
+concerned, the prodigious difference in this respect between the workers
+and the perfect females, would have been far better exemplified by the
+hive-bee.  If a working ant or other neuter insect had been an animal in
+the ordinary state, I should have unhesitatingly assumed that all its
+characters had been slowly acquired through natural selection; namely, by
+an individual having been born with some slight profitable modification of
+structure, this being inherited by its offspring, which again varied and
+were again selected, and so onwards.  But with the working ant we have an
+insect differing greatly from its parents, yet absolutely sterile; so that
+it could never have transmitted successively acquired modifications of
+structure or instinct to its progeny.  It may well be asked how is it
+possible to reconcile this case with the theory of natural selection?
+</para>
+
+<para>
+First, let it be remembered that we have innumerable instances, both in our
+domestic productions and in those in a state of nature, of all sorts of
+differences of structure which have become correlated to certain ages, and
+to either sex.  We have differences correlated not only to one sex, but to
+that short period alone when the reproductive system is active, as in the
+nuptial plumage of many birds, and in the hooked jaws of the male salmon. 
+We have even slight differences in the horns of different breeds of cattle
+in relation to an artificially imperfect state of the male sex; for oxen of
+certain breeds have longer horns than in other breeds, in comparison with
+the horns of the bulls or cows of these same breeds.  Hence I can see no
+real difficulty in any character having become correlated with the sterile
+condition of certain members of insect-communities:  the difficulty lies in
+understanding how such correlated modifications of structure could have
+been slowly accumulated by natural selection.
+</para>
+
+<para>
+This difficulty, though appearing insuperable, is lessened, or, as I
+believe, disappears, when it is remembered that selection may be applied to
+the family, as well as to the individual, and may thus gain the desired
+end.  Thus, a well-flavoured vegetable is cooked, and the individual is
+destroyed; but the horticulturist sows seeds of the same stock, and
+confidently expects to get nearly the same variety; breeders of cattle wish
+the flesh and fat to be well marbled together; the animal has been
+slaughtered, but the breeder goes with confidence to the same family.  I
+have such faith in the powers of selection, that I do not doubt that a
+breed of cattle, always yielding oxen with extraordinarily long horns,
+could be slowly formed by carefully watching which individual bulls and
+cows, when matched, produced oxen with the longest horns; and yet no one ox
+could ever have propagated its kind.  Thus I believe it has been with
+social insects:  a slight modification of structure, or instinct,
+correlated with the sterile condition of certain members of the community,
+has been advantageous to the community:  consequently the fertile males and
+females of the same community flourished, and transmitted to their fertile
+offspring a tendency to produce sterile members having the same
+modification.  And I believe that this process has been repeated, until
+that prodigious amount of difference between the fertile and sterile
+females of the same species has been produced, which we see in many social
+insects.
+</para>
+
+<para>
+But we have not as yet touched on the climax of the difficulty; namely, the
+fact that the neuters of several ants differ, not only from the fertile
+females and males, but from each other, sometimes to an almost incredible
+degree, and are thus divided into two or even three castes.  The castes,
+moreover, do not generally graduate into each other, but are perfectly well
+defined; being as distinct from each other, as are any two species of the
+same genus, or rather as any two genera of the same family.  Thus in
+Eciton, there are working and soldier neuters, with jaws and instincts
+extraordinarily different:  in Cryptocerus, the workers of one caste alone
+carry a wonderful sort of shield on their heads, the use of which is quite
+unknown:  in the Mexican Myrmecocystus, the workers of one caste never
+leave the nest; they are fed by the workers of another caste, and they have
+an enormously developed abdomen which secretes a sort of honey, supplying
+the place of that excreted by the aphides, or the domestic cattle as they
+may be called, which our European ants guard or imprison.
+</para>
+
+<para>
+It will indeed be thought that I have an overweening confidence in the
+principle of natural selection, when I do not admit that such wonderful and
+well-established facts at once annihilate my theory.  In the simpler case
+of neuter insects all of one caste or of the same kind, which have been
+rendered by natural selection, as I believe to be quite possible, different
+from the fertile males and females,--in this case, we may safely conclude
+from the analogy of ordinary variations, that each successive, slight,
+profitable modification did not probably at first appear in all the
+individual neuters in the same nest, but in a few alone; and that by the
+long-continued selection of the fertile parents which produced most neuters
+with the profitable modification, all the neuters ultimately came to have
+the desired character.  On this view we ought occasionally to find
+neuter-insects of the same species, in the same nest, presenting gradations
+of structure; and this we do find, even often, considering how few
+neuter-insects out of Europe have been carefully examined.  Mr. F. Smith
+has shown how surprisingly the neuters of several British ants differ from
+each other in size and sometimes in colour; and that the extreme forms can
+sometimes be perfectly linked together by individuals taken out of the same
+nest:  I have myself compared perfect gradations of this kind.  It often
+happens that the larger or the smaller sized workers are the most numerous;
+or that both large and small are numerous, with those of an intermediate
+size scanty in numbers.  Formica flava has larger and smaller workers, with
+some of intermediate size; and, in this species, as Mr. F. Smith has
+observed, the larger workers have simple eyes (ocelli), which though small
+can be plainly distinguished, whereas the smaller workers have their ocelli
+rudimentary.  Having carefully dissected several specimens of these
+workers, I can affirm that the eyes are far more rudimentary in the smaller
+workers than can be accounted for merely by their proportionally lesser
+size; and I fully believe, though I dare not assert so positively, that the
+workers of intermediate size have their ocelli in an exactly intermediate
+condition.  So that we here have two bodies of sterile workers in the same
+nest, differing not only in size, but in their organs of vision, yet
+connected by some few members in an intermediate condition.  I may digress
+by adding, that if the smaller workers had been the most useful to the
+community, and those males and females had been continually selected, which
+produced more and more of the smaller workers, until all the workers had
+come to be in this condition; we should then have had a species of ant with
+neuters very nearly in the same condition with those of Myrmica.  For the
+workers of Myrmica have not even rudiments of ocelli, though the male and
+female ants of this genus have well-developed ocelli.
+</para>
+
+<para>
+I may give one other case:  so confidently did I expect to find gradations
+in important points of structure between the different castes of neuters in
+the same species, that I gladly availed myself of Mr. F. Smith's offer of
+numerous specimens from the same nest of the driver ant (Anomma) of West
+Africa.  The reader will perhaps best appreciate the amount of difference
+in these workers, by my giving not the actual measurements, but a strictly
+accurate illustration:  the difference was the same as if we were to see a
+set of workmen building a house of whom many were five feet four inches
+high, and many sixteen feet high; but we must suppose that the larger
+workmen had heads four instead of three times as big as those of the
+smaller men, and jaws nearly five times as big.  The jaws, moreover, of the
+working ants of the several sizes differed wonderfully in shape, and in the
+form and number of the teeth.  But the important fact for us is, that
+though the workers can be grouped into castes of different sizes, yet they
+graduate insensibly into each other, as does the widely-different structure
+of their jaws.  I speak confidently on this latter point, as Mr. Lubbock
+made drawings for me with the camera lucida of the jaws which I had
+dissected from the workers of the several sizes.
+</para>
+
+<para>
+With these facts before me, I believe that natural selection, by acting on
+the fertile parents, could form a species which should regularly produce
+neuters, either all of large size with one form of jaw, or all of small
+size with jaws having a widely different structure; or lastly, and this is
+our climax of difficulty, one set of workers of one size and structure, and
+simultaneously another set of workers of a different size and structure;--a
+graduated series having been first formed, as in the case of the driver
+ant, and then the extreme forms, from being the most useful to the
+community, having been produced in greater and greater numbers through the
+natural selection of the parents which generated them; until none with an
+intermediate structure were produced.
+</para>
+
+<para>
+Thus, as I believe, the wonderful fact of two distinctly defined castes of
+sterile workers existing in the same nest, both widely different from each
+other and from their parents, has originated.  We can see how useful their
+production may have been to a social community of insects, on the same
+principle that the division of labour is useful to civilised man.  As ants
+work by inherited instincts and by inherited tools or weapons, and not by
+acquired knowledge and manufactured instruments, a perfect division of
+labour could be effected with them only by the workers being sterile; for
+had they been fertile, they would have intercrossed, and their instincts
+and structure would have become blended.  And nature has, as I believe,
+effected this admirable division of labour in the communities of ants, by
+the means of natural selection.  But I am bound to confess, that, with all
+my faith in this principle, I should never have anticipated that natural
+selection could have been efficient in so high a degree, had not the case
+of these neuter insects convinced me of the fact.  I have, therefore,
+discussed this case, at some little but wholly insufficient length, in
+order to show the power of natural selection, and likewise because this is
+by far the most serious special difficulty, which my theory has
+encountered.  The case, also, is very interesting, as it proves that with
+animals, as with plants, any amount of modification in structure can be
+effected by the accumulation of numerous, slight, and as we must call them
+accidental, variations, which are in any manner profitable, without
+exercise or habit having come into play.  For no amount of exercise, or
+habit, or volition, in the utterly sterile members of a community could
+possibly have affected the structure or instincts of the fertile members,
+which alone leave descendants.  I am surprised that no one has advanced
+this demonstrative case of neuter insects, against the well-known doctrine
+of Lamarck.
+</para>
+
+<para>
+Summary. -- I have endeavoured briefly in this chapter to show that the
+mental qualities of our domestic animals vary, and that the variations are
+inherited.  Still more briefly I have attempted to show that instincts vary
+slightly in a state of nature.  No one will dispute that instincts are of
+the highest importance to each animal.  Therefore I can see no difficulty,
+under changing conditions of life, in natural selection accumulating slight
+modifications of instinct to any extent, in any useful direction.  In some
+cases habit or use and disuse have probably come into play.  I do not
+pretend that the facts given in this chapter strengthen in any great degree
+my theory; but none of the cases of difficulty, to the best of my judgment,
+annihilate it.  On the other hand, the fact that instincts are not always
+absolutely perfect and are liable to mistakes;--that no instinct has been
+produced for the exclusive good of other animals, but that each animal
+takes advantage of the instincts of others;--that the canon in natural
+history, of 'natura non facit saltum' is applicable to instincts as well as
+to corporeal structure, and is plainly explicable on the foregoing views,
+but is otherwise inexplicable,--all tend to corroborate the theory of
+natural selection.
+</para>
+
+<para>
+This theory is, also, strengthened by some few other facts in regard to
+instincts; as by that common case of closely allied, but certainly
+distinct, species, when inhabiting distant parts of the world and living
+under considerably different conditions of life, yet often retaining nearly
+the same instincts.  For instance, we can understand on the principle of
+inheritance, how it is that the thrush of South America lines its nest with
+mud, in the same peculiar manner as does our British thrush:  how it is
+that the male wrens (Troglodytes) of North America, build 'cock-nests,' to
+roost in, like the males of our distinct Kitty-wrens,--a habit wholly
+unlike that of any other known bird.  Finally, it may not be a logical
+deduction, but to my imagination it is far more satisfactory to look at
+such instincts as the young cuckoo ejecting its foster-brothers,--ants
+making slaves,--the larvae of ichneumonidae feeding within the live bodies
+of caterpillars,--not as specially endowed or created instincts, but as
+small consequences of one general law, leading to the advancement of all
+organic beings, namely, multiply, vary, let the strongest live and the
+weakest die.
+</para>
+
+</chapter>
+
+<chapter>
+<chapheader>
+
+<chapnum>Chapter VIII</chapnum>
+
+<title>Hybridism</title>
+
+<chapsummary>
+Distinction between the sterility of first crosses and of hybrids --
+Sterility various in degree, not universal, affected by close
+interbreeding, removed by domestication -- Laws governing the sterility of
+hybrids -- Sterility not a special endowment, but incidental on other
+differences -- Causes of the sterility of first crosses and of hybrids --
+Parallelism between the effects of changed conditions of life and crossing
+-- Fertility of varieties when crossed and of their mongrel offspring not
+universal -- Hybrids and mongrels compared independently of their fertility
+-- Summary.
+</chapsummary>
+</chapheader>
+
+<para>
+The view generally entertained by naturalists is that species, when
+intercrossed, have been specially endowed with the quality of sterility, in
+order to prevent the confusion of all organic forms.  This view certainly
+seems at first probable, for species within the same country could hardly
+have kept distinct had they been capable of crossing freely.  The
+importance of the fact that hybrids are very generally sterile, has, I
+think, been much underrated by some late writers.  On the theory of natural
+selection the case is especially important, inasmuch as the sterility of
+hybrids could not possibly be of any advantage to them, and therefore could
+not have been acquired by the continued preservation of successive
+profitable degrees of sterility.  I hope, however, to be able to show that
+sterility is not a specially acquired or endowed quality, but is incidental
+on other acquired differences.
+</para>
+
+<para>
+In treating this subject, two classes of facts, to a large extent
+fundamentally different, have generally been confounded together; namely,
+the sterility of two species when first crossed, and the sterility of the
+hybrids produced from them.
+</para>
+
+<para>
+Pure species have of course their organs of reproduction in a perfect
+condition, yet when intercrossed they produce either few or no offspring. 
+Hybrids, on the other hand, have their reproductive organs functionally
+impotent, as may be clearly seen in the state of the male element in both
+plants and animals; though the organs themselves are perfect in structure,
+as far as the microscope reveals.  In the first case the two sexual
+elements which go to form the embryo are perfect; in the second case they
+are either not at all developed, or are imperfectly developed.  This
+distinction is important, when the cause of the sterility, which is common
+to the two cases, has to be considered.  The distinction has probably been
+slurred over, owing to the sterility in both cases being looked on as a
+special endowment, beyond the province of our reasoning powers.
+</para>
+
+<para>
+The fertility of varieties, that is of the forms known or believed to have
+descended from common parents, when intercrossed, and likewise the
+fertility of their mongrel offspring, is, on my theory, of equal importance
+with the sterility of species; for it seems to make a broad and clear
+distinction between varieties and species.
+</para>
+
+<para>
+First, for the sterility of species when crossed and of their hybrid
+offspring.  It is impossible to study the several memoirs and works of
+those two conscientious and admirable observers, Kolreuter and Gartner, who
+almost devoted their lives to this subject, without being deeply impressed
+with the high generality of some degree of sterility.  Kolreuter makes the
+rule universal; but then he cuts the knot, for in ten cases in which he
+found two forms, considered by most authors as distinct species, quite
+fertile together, he unhesitatingly ranks them as varieties.  Gartner,
+also, makes the rule equally universal; and he disputes the entire
+fertility of Kolreuter's ten cases.  But in these and in many other cases,
+Gartner is obliged carefully to count the seeds, in order to show that
+there is any degree of sterility.  He always compares the maximum number of
+seeds produced by two species when crossed and by their hybrid offspring,
+with the average number produced by both pure parent-species in a state of
+nature.  But a serious cause of error seems to me to be here introduced:  a
+plant to be hybridised must be castrated, and, what is often more
+important, must be secluded in order to prevent pollen being brought to it
+by insects from other plants.  Nearly all the plants experimentised on by
+Gartner were potted, and apparently were kept in a chamber in his house. 
+That these processes are often injurious to the fertility of a plant cannot
+be doubted; for Gartner gives in his table about a score of cases of plants
+which he castrated, and artificially fertilised with their own pollen, and
+(excluding all cases such as the Leguminosae, in which there is an
+acknowledged difficulty in the manipulation) half of these twenty plants
+had their fertility in some degree impaired.  Moreover, as Gartner during
+several years repeatedly crossed the primrose and cowslip, which we have
+such good reason to believe to be varieties, and only once or twice
+succeeded in getting fertile seed; as he found the common red and blue
+pimpernels (Anagallis arvensis and coerulea), which the best botanists rank
+as varieties, absolutely sterile together; and as he came to the same
+conclusion in several other analogous cases; it seems to me that we may
+well be permitted to doubt whether many other species are really so
+sterile, when intercrossed, as Gartner believes.
+</para>
+
+<para>
+It is certain, on the one hand, that the sterility of various species when
+crossed is so different in degree and graduates away so insensibly, and, on
+the other hand, that the fertility of pure species is so easily affected by
+various circumstances, that for all practical purposes it is most difficult
+to say where perfect fertility ends and sterility begins.  I think no
+better evidence of this can be required than that the two most experienced
+observers who have ever lived, namely, Kolreuter and Gartner, should have
+arrived at diametrically opposite conclusions in regard to the very same
+species.  It is also most instructive to compare--but I have not space here
+to enter on details--the evidence advanced by our best botanists on the
+question whether certain doubtful forms should be ranked as species or
+varieties, with the evidence from fertility adduced by different
+hybridisers, or by the same author, from experiments made during different
+years.  It can thus be shown that neither sterility nor fertility affords
+any clear distinction between species and varieties; but that the evidence
+from this source graduates away, and is doubtful in the same degree as is
+the evidence derived from other constitutional and structural differences.
+</para>
+
+<para>
+In regard to the sterility of hybrids in successive generations; though
+Gartner was enabled to rear some hybrids, carefully guarding them from a
+cross with either pure parent, for six or seven, and in one case for ten
+generations, yet he asserts positively that their fertility never
+increased, but generally greatly decreased.  I do not doubt that this is
+usually the case, and that the fertility often suddenly decreases in the
+first few generations.  Nevertheless I believe that in all these
+experiments the fertility has been diminished by an independent cause,
+namely, from close interbreeding.  I have collected so large a body of
+facts, showing that close interbreeding lessens fertility, and, on the
+other hand, that an occasional cross with a distinct individual or variety
+increases fertility, that I cannot doubt the correctness of this almost
+universal belief amongst breeders.  Hybrids are seldom raised by
+experimentalists in great numbers; and as the parent-species, or other
+allied hybrids, generally grow in the same garden, the visits of insects
+must be carefully prevented during the flowering season:  hence hybrids
+will generally be fertilised during each generation by their own individual
+pollen; and I am convinced that this would be injurious to their fertility,
+already lessened by their hybrid origin.  I am strengthened in this
+conviction by a remarkable statement repeatedly made by Gartner, namely,
+that if even the less fertile hybrids be artificially fertilised with
+hybrid pollen of the same kind, their fertility, notwithstanding the
+frequent ill effects of manipulation, sometimes decidedly increases, and
+goes on increasing.  Now, in artificial fertilisation pollen is as often
+taken by chance (as I know from my own experience) from the anthers of
+another flower, as from the anthers of the flower itself which is to be
+fertilised; so that a cross between two flowers, though probably on the
+same plant, would be thus effected.  Moreover, whenever complicated
+experiments are in progress, so careful an observer as Gartner would have
+castrated his hybrids, and this would have insured in each generation a
+cross with the pollen from a distinct flower, either from the same plant or
+from another plant of the same hybrid nature.  And thus, the strange fact
+of the increase of fertility in the successive generations of artificially
+fertilised hybrids may, I believe, be accounted for by close interbreeding
+having been avoided.
+</para>
+
+<para>
+Now let us turn to the results arrived at by the third most experienced
+hybridiser, namely, the Hon. and Rev. W. Herbert.  He is as emphatic in his
+conclusion that some hybrids are perfectly fertile--as fertile as the pure
+parent-species--as are Kolreuter and Gartner that some degree of sterility
+between distinct species is a universal law of nature.  He experimentised
+on some of the very same species as did Gartner.  The difference in their
+results may, I think, be in part accounted for by Herbert's great
+horticultural skill, and by his having hothouses at his command.  Of his
+many important statements I will here give only a single one as an example,
+namely, that 'every ovule in a pod of Crinum capense fertilised by C.
+revolutum produced a plant, which (he says) I never saw to occur in a case
+of its natural fecundation.'  So that we here have perfect, or even more
+than commonly perfect, fertility in a first cross between two distinct
+species.
+</para>
+
+<para>
+This case of the Crinum leads me to refer to a most singular fact, namely,
+that there are individual plants, as with certain species of Lobelia, and
+with all the species of the genus Hippeastrum, which can be far more easily
+fertilised by the pollen of another and distinct species, than by their own
+pollen.  For these plants have been found to yield seed to the pollen of a
+distinct species, though quite sterile with their own pollen,
+notwithstanding that their own pollen was found to be perfectly good, for
+it fertilised distinct species.  So that certain individual plants and all
+the individuals of certain species can actually be hybridised much more
+readily than they can be self-fertilised!  For instance, a bulb of
+Hippeastrum aulicum produced four flowers; three were fertilised by Herbert
+with their own pollen, and the fourth was subsequently fertilised by the
+pollen of a compound hybrid descended from three other and distinct
+species:  the result was that 'the ovaries of the three first flowers soon
+ceased to grow, and after a few days perished entirely, whereas the pod
+impregnated by the pollen of the hybrid made vigorous growth and rapid
+progress to maturity, and bore good seed, which vegetated freely.'  In a
+letter to me, in 1839, Mr. Herbert told me that he had then tried the
+experiment during five years, and he continued to try it during several
+subsequent years, and always with the same result.  This result has, also,
+been confirmed by other observers in the case of Hippeastrum with its
+sub-genera, and in the case of some other genera, as Lobelia, Passiflora
+and Verbascum.  Although the plants in these experiments appeared perfectly
+healthy, and although both the ovules and pollen of the same flower were
+perfectly good with respect to other species, yet as they were functionally
+imperfect in their mutual self-action, we must infer that the plants were
+in an unnatural state.  Nevertheless these facts show on what slight and
+mysterious causes the lesser or greater fertility of species when crossed,
+in comparison with the same species when self-fertilised, sometimes
+depends.
+</para>
+
+<para>
+The practical experiments of horticulturists, though not made with
+scientific precision, deserve some notice.  It is notorious in how
+complicated a manner the species of Pelargonium, Fuchsia, Calceolaria,
+Petunia, Rhododendron, &amp;c., have been crossed, yet many of these hybrids
+seed freely.  For instance, Herbert asserts that a hybrid from Calceolaria
+integrifolia and plantaginea, species most widely dissimilar in general
+habit, 'reproduced itself as perfectly as if it had been a natural species
+from the mountains of Chile.'  I have taken some pains to ascertain the
+degree of fertility of some of the complex crosses of Rhododendrons, and I
+am assured that many of them are perfectly fertile.  Mr. C. Noble, for
+instance, informs me that he raises stocks for grafting from a hybrid
+between Rhod. Ponticum and Catawbiense, and that this hybrid 'seeds as
+freely as it is possible to imagine.'  Had hybrids, when fairly treated,
+gone on decreasing in fertility in each successive generation, as Gartner
+believes to be the case, the fact would have been notorious to nurserymen. 
+Horticulturists raise large beds of the same hybrids, and such alone are
+fairly treated, for by insect agency the several individuals of the same
+hybrid variety are allowed to freely cross with each other, and the
+injurious influence of close interbreeding is thus prevented.  Any one may
+readily convince himself of the efficiency of insect-agency by examining
+the flowers of the more sterile kinds of hybrid rhododendrons, which
+produce no pollen, for he will find on their stigmas plenty of pollen
+brought from other flowers.
+</para>
+
+<para>
+In regard to animals, much fewer experiments have been carefully tried than
+with plants.  If our systematic arrangements can be trusted, that is if the
+genera of animals are as distinct from each other, as are the genera of
+plants, then we may infer that animals more widely separated in the scale
+of nature can be more easily crossed than in the case of plants; but the
+hybrids themselves are, I think, more sterile.  I doubt whether any case of
+a perfectly fertile hybrid animal can be considered as thoroughly well
+authenticated.  It should, however, be borne in mind that, owing to few
+animals breeding freely under confinement, few experiments have been fairly
+tried:  for instance, the canary-bird has been crossed with nine other
+finches, but as not one of these nine species breeds freely in confinement,
+we have no right to expect that the first crosses between them and the
+canary, or that their hybrids, should be perfectly fertile.  Again, with
+respect to the fertility in successive generations of the more fertile
+hybrid animals, I hardly know of an instance in which two families of the
+same hybrid have been raised at the same time from different parents, so as
+to avoid the ill effects of close interbreeding.  On the contrary, brothers
+and sisters have usually been crossed in each successive generation, in
+opposition to the constantly repeated admonition of every breeder.  And in
+this case, it is not at all surprising that the inherent sterility in the
+hybrids should have gone on increasing.  If we were to act thus, and pair
+brothers and sisters in the case of any pure animal, which from any cause
+had the least tendency to sterility, the breed would assuredly be lost in a
+very few generations.
+</para>
+
+<para>
+Although I do not know of any thoroughly well-authenticated cases of
+perfectly fertile hybrid animals, I have some reason to believe that the
+hybrids from Cervulus vaginalis and Reevesii, and from Phasianus colchicus
+with P. torquatus and with P. versicolor are perfectly fertile.  The
+hybrids from the common and Chinese geese (A. cygnoides), species which are
+so different that they are generally ranked in distinct genera, have often
+bred in this country with either pure parent, and in one single instance
+they have bred inter se.  This was effected by Mr. Eyton, who raised two
+hybrids from the same parents but from different hatches; and from these
+two birds he raised no less than eight hybrids (grandchildren of the pure
+geese) from one nest.  In India, however, these cross-bred geese must be
+far more fertile; for I am assured by two eminently capable judges, namely
+Mr. Blyth and Capt. Hutton, that whole flocks of these crossed geese are
+kept in various parts of the country; and as they are kept for profit,
+where neither pure parent-species exists, they must certainly be highly
+fertile.
+</para>
+
+<para>
+A doctrine which originated with Pallas, has been largely accepted by
+modern naturalists; namely, that most of our domestic animals have
+descended from two or more aboriginal species, since commingled by
+intercrossing.  On this view, the aboriginal species must either at first
+have produced quite fertile hybrids, or the hybrids must have become in
+subsequent generations quite fertile under domestication.  This latter
+alternative seems to me the most probable, and I am inclined to believe in
+its truth, although it rests on no direct evidence.  I believe, for
+instance, that our dogs have descended from several wild stocks; yet, with
+perhaps the exception of certain indigenous domestic dogs of South America,
+all are quite fertile together; and analogy makes me greatly doubt, whether
+the several aboriginal species would at first have freely bred together and
+have produced quite fertile hybrids.  So again there is reason to believe
+that our European and the humped Indian cattle are quite fertile together;
+but from facts communicated to me by Mr. Blyth, I think they must be
+considered as distinct species.  On this view of the origin of many of our
+domestic animals, we must either give up the belief of the almost universal
+sterility of distinct species of animals when crossed; or we must look at
+sterility, not as an indelible characteristic, but as one capable of being
+removed by domestication.
+</para>
+
+<para>
+Finally, looking to all the ascertained facts on the intercrossing of
+plants and animals, it may be concluded that some degree of sterility, both
+in first crosses and in hybrids, is an extremely general result; but that
+it cannot, under our present state of knowledge, be considered as
+absolutely universal.
+</para>
+
+<para>
+Laws governing the Sterility of first Crosses and of Hybrids. -- We will
+now consider a little more in detail the circumstances and rules governing
+the sterility of first crosses and of hybrids.  Our chief object will be to
+see whether or not the rules indicate that species have specially been
+endowed with this quality, in order to prevent their crossing and blending
+together in utter confusion.  The following rules and conclusions are
+chiefly drawn up from Gartner's admirable work on the hybridisation of
+plants.  I have taken much pains to ascertain how far the rules apply to
+animals, and considering how scanty our knowledge is in regard to hybrid
+animals, I have been surprised to find how generally the same rules apply
+to both kingdoms.
+</para>
+
+<para>
+It has been already remarked, that the degree of fertility, both of first
+crosses and of hybrids, graduates from zero to perfect fertility.  It is
+surprising in how many curious ways this gradation can be shown to exist;
+but only the barest outline of the facts can here be given.  When pollen
+from a plant of one family is placed on the stigma of a plant of a distinct
+family, it exerts no more influence than so much inorganic dust.  From this
+absolute zero of fertility, the pollen of different species of the same
+genus applied to the stigma of some one species, yields a perfect gradation
+in the number of seeds produced, up to nearly complete or even quite
+complete fertility; and, as we have seen, in certain abnormal cases, even
+to an excess of fertility, beyond that which the plant's own pollen will
+produce.  So in hybrids themselves, there are some which never have
+produced, and probably never would produce, even with the pollen of either
+pure parent, a single fertile seed:  but in some of these cases a first
+trace of fertility may be detected, by the pollen of one of the pure
+parent-species causing the flower of the hybrid to wither earlier than it
+otherwise would have done; and the early withering of the flower is well
+known to be a sign of incipient fertilisation.  From this extreme degree of
+sterility we have self-fertilised hybrids producing a greater and greater
+number of seeds up to perfect fertility.
+</para>
+
+<para>
+Hybrids from two species which are very difficult to cross, and which
+rarely produce any offspring, are generally very sterile; but the
+parallelism between the difficulty of making a first cross, and the
+sterility of the hybrids thus produced--two classes of facts which are
+generally confounded together--is by no means strict.  There are many
+cases, in which two pure species can be united with unusual facility, and
+produce numerous hybrid-offspring, yet these hybrids are remarkably
+sterile.  On the other hand, there are species which can be crossed very
+rarely, or with extreme difficulty, but the hybrids, when at last produced,
+are very fertile.  Even within the limits of the same genus, for instance
+in Dianthus, these two opposite cases occur.
+</para>
+
+<para>
+The fertility, both of first crosses and of hybrids, is more easily
+affected by unfavourable conditions, than is the fertility of pure species. 
+But the degree of fertility is likewise innately variable; for it is not
+always the same when the same two species are crossed under the same
+circumstances, but depends in part upon the constitution of the individuals
+which happen to have been chosen for the experiment.  So it is with
+hybrids, for their degree of fertility is often found to differ greatly in
+the several individuals raised from seed out of the same capsule and
+exposed to exactly the same conditions.
+</para>
+
+<para>
+By the term systematic affinity is meant, the resemblance between species
+in structure and in constitution, more especially in the structure of parts
+which are of high physiological importance and which differ little in the
+allied species.  Now the fertility of first crosses between species, and of
+the hybrids produced from them, is largely governed by their systematic
+affinity.  This is clearly shown by hybrids never having been raised
+between species ranked by systematists in distinct families; and on the
+other hand, by very closely allied species generally uniting with facility. 
+But the correspondence between systematic affinity and the facility of
+crossing is by no means strict.  A multitude of cases could be given of
+very closely allied species which will not unite, or only with extreme
+difficulty; and on the other hand of very distinct species which unite with
+the utmost facility.  In the same family there may be a genus, as Dianthus,
+in which very many species can most readily be crossed; and another genus,
+as Silene, in which the most persevering efforts have failed to produce
+between extremely close species a single hybrid.  Even within the limits of
+the same genus, we meet with this same difference; for instance, the many
+species of Nicotiana have been more largely crossed than the species of
+almost any other genus; but Gartner found that N. acuminata, which is not a
+particularly distinct species, obstinately failed to fertilise, or to be
+fertilised by, no less than eight other species of Nicotiana.  Very many
+analogous facts could be given.
+</para>
+
+<para>
+No one has been able to point out what kind, or what amount, of difference
+in any recognisable character is sufficient to prevent two species
+crossing.  It can be shown that plants most widely different in habit and
+general appearance, and having strongly marked differences in every part of
+the flower, even in the pollen, in the fruit, and in the cotyledons, can be
+crossed.  Annual and perennial plants, deciduous and evergreen trees,
+plants inhabiting different stations and fitted for extremely different
+climates, can often be crossed with ease.
+</para>
+
+<para>
+By a reciprocal cross between two species, I mean the case, for instance,
+of a stallion-horse being first crossed with a female-ass, and then a
+male-ass with a mare:  these two species may then be said to have been
+reciprocally crossed.  There is often the widest possible difference in the
+facility of making reciprocal crosses.  Such cases are highly important,
+for they prove that the capacity in any two species to cross is often
+completely independent of their systematic affinity, or of any recognisable
+difference in their whole organisation.  On the other hand, these cases
+clearly show that the capacity for crossing is connected with
+constitutional differences imperceptible by us, and confined to the
+reproductive system.  This difference in the result of reciprocal crosses
+between the same two species was long ago observed by Kolreuter.  To give
+an instance:  Mirabilis jalappa can easily be fertilised by the pollen of
+M. longiflora, and the hybrids thus produced are sufficiently fertile; but
+Kolreuter tried more than two hundred times, during eight following years,
+to fertilise reciprocally M. longiflora with the pollen of M. jalappa, and
+utterly failed.  Several other equally striking cases could be given. 
+Thuret has observed the same fact with certain sea-weeds or Fuci.  Gartner,
+moreover, found that this difference of facility in making reciprocal
+crosses is extremely common in a lesser degree.  He has observed it even
+between forms so closely related (as Matthiola annua and glabra) that many
+botanists rank them only as varieties.  It is also a remarkable fact, that
+hybrids raised from reciprocal crosses, though of course compounded of the
+very same two species, the one species having first been used as the father
+and then as the mother, generally differ in fertility in a small, and
+occasionally in a high degree.
+</para>
+
+<para>
+Several other singular rules could be given from Gartner:  for instance,
+some species have a remarkable power of crossing with other species; other
+species of the same genus have a remarkable power of impressing their
+likeness on their hybrid offspring; but these two powers do not at all
+necessarily go together.  There are certain hybrids which instead of
+having, as is usual, an intermediate character between their two parents,
+always closely resemble one of them; and such hybrids, though externally so
+like one of their pure parent-species, are with rare exceptions extremely
+sterile.  So again amongst hybrids which are usually intermediate in
+structure between their parents, exceptional and abnormal individuals
+sometimes are born, which closely resemble one of their pure parents; and
+these hybrids are almost always utterly sterile, even when the other
+hybrids raised from seed from the same capsule have a considerable degree
+of fertility.  These facts show how completely fertility in the hybrid is
+independent of its external resemblance to either pure parent.
+</para>
+
+<para>
+Considering the several rules now given, which govern the fertility of
+first crosses and of hybrids, we see that when forms, which must be
+considered as good and distinct species, are united, their fertility
+graduates from zero to perfect fertility, or even to fertility under
+certain conditions in excess.  That their fertility, besides being
+eminently susceptible to favourable and unfavourable conditions, is
+innately variable.  That it is by no means always the same in degree in the
+first cross and in the hybrids produced from this cross.  That the
+fertility of hybrids is not related to the degree in which they resemble in
+external appearance either parent.  And lastly, that the facility of making
+a first cross between any two species is not always governed by their
+systematic affinity or degree of resemblance to each other.  This latter
+statement is clearly proved by reciprocal crosses between the same two
+species, for according as the one species or the other is used as the
+father or the mother, there is generally some difference, and occasionally
+the widest possible difference, in the facility of effecting an union.  The
+hybrids, moreover, produced from reciprocal crosses often differ in
+fertility.
+</para>
+
+<para>
+Now do these complex and singular rules indicate that species have been
+endowed with sterility simply to prevent their becoming confounded in
+nature?  I think not.  For why should the sterility be so extremely
+different in degree, when various species are crossed, all of which we must
+suppose it would be equally important to keep from blending together?  Why
+should the degree of sterility be innately variable in the individuals of
+the same species?  Why should some species cross with facility, and yet
+produce very sterile hybrids; and other species cross with extreme
+difficulty, and yet produce fairly fertile hybrids?  Why should there often
+be so great a difference in the result of a reciprocal cross between the
+same two species?  Why, it may even be asked, has the production of hybrids
+been permitted? to grant to species the special power of producing hybrids,
+and then to stop their further propagation by different degrees of
+sterility, not strictly related to the facility of the first union between
+their parents, seems to be a strange arrangement.
+</para>
+
+<para>
+The foregoing rules and facts, on the other hand, appear to me clearly to
+indicate that the sterility both of first crosses and of hybrids is simply
+incidental or dependent on unknown differences, chiefly in the reproductive
+systems, of the species which are crossed.  The differences being of so
+peculiar and limited a nature, that, in reciprocal crosses between two
+species the male sexual element of the one will often freely act on the
+female sexual element of the other, but not in a reversed direction.  It
+will be advisable to explain a little more fully by an example what I mean
+by sterility being incidental on other differences, and not a specially
+endowed quality.  As the capacity of one plant to be grafted or budded on
+another is so entirely unimportant for its welfare in a state of nature, I
+presume that no one will suppose that this capacity is a specially endowed
+quality, but will admit that it is incidental on differences in the laws of
+growth of the two plants.  We can sometimes see the reason why one tree
+will not take on another, from differences in their rate of growth, in the
+hardness of their wood, in the period of the flow or nature of their sap,
+&amp;c.; but in a multitude of cases we can assign no reason whatever.  Great
+diversity in the size of two plants, one being woody and the other
+herbaceous, one being evergreen and the other deciduous, and adaptation to
+widely different climates, does not always prevent the two grafting
+together.  As in hybridisation, so with grafting, the capacity is limited
+by systematic affinity, for no one has been able to graft trees together
+belonging to quite distinct families; and, on the other hand, closely
+allied species, and varieties of the same species, can usually, but not
+invariably, be grafted with ease.  But this capacity, as in hybridisation,
+is by no means absolutely governed by systematic affinity.  Although many
+distinct genera within the same family have been grafted together, in other
+cases species of the same genus will not take on each other.  The pear can
+be grafted far more readily on the quince, which is ranked as a distinct
+genus, than on the apple, which is a member of the same genus.  Even
+different varieties of the pear take with different degrees of facility on
+the quince; so do different varieties of the apricot and peach on certain
+varieties of the plum.
+</para>
+
+<para>
+As Gartner found that there was sometimes an innate difference in different
+individuals of the same two species in crossing; so Sagaret believes this
+to be the case with different individuals of the same two species in being
+grafted together.  As in reciprocal crosses, the facility of effecting an
+union is often very far from equal, so it sometimes is in grafting; the
+common gooseberry, for instance, cannot be grafted on the currant, whereas
+the currant will take, though with difficulty, on the gooseberry.
+</para>
+
+<para>
+We have seen that the sterility of hybrids, which have their reproductive
+organs in an imperfect condition, is a very different case from the
+difficulty of uniting two pure species, which have their reproductive
+organs perfect; yet these two distinct cases run to a certain extent
+parallel.  Something analogous occurs in grafting; for Thouin found that
+three species of Robinia, which seeded freely on their own roots, and which
+could be grafted with no great difficulty on another species, when thus
+grafted were rendered barren.  On the other hand, certain species of
+Sorbus, when grafted on other species, yielded twice as much fruit as when
+on their own roots.  We are reminded by this latter fact of the
+extraordinary case of Hippeastrum, Lobelia, &amp;c., which seeded much more
+freely when fertilised with the pollen of distinct species, than when
+self-fertilised with their own pollen.
+</para>
+
+<para>
+We thus see, that although there is a clear and fundamental difference
+between the mere adhesion of grafted stocks, and the union of the male and
+female elements in the act of reproduction, yet that there is a rude degree
+of parallelism in the results of grafting and of crossing distinct species. 
+And as we must look at the curious and complex laws governing the facility
+with which trees can be grafted on each other as incidental on unknown
+differences in their vegetative systems, so I believe that the still more
+complex laws governing the facility of first crosses, are incidental on
+unknown differences, chiefly in their reproductive systems.  These
+differences, in both cases, follow to a certain extent, as might have been
+expected, systematic affinity, by which every kind of resemblance and
+dissimilarity between organic beings is attempted to be expressed.  The
+facts by no means seem to me to indicate that the greater or lesser
+difficulty of either grafting or crossing together various species has been
+a special endowment; although in the case of crossing, the difficulty is as
+important for the endurance and stability of specific forms, as in the case
+of grafting it is unimportant for their welfare.
+</para>
+
+<para>
+Causes of the Sterility of first Crosses and of Hybrids. -- We may now look
+a little closer at the probable causes of the sterility of first crosses
+and of hybrids.  These two cases are fundamentally different, for, as just
+remarked, in the union of two pure species the male and female sexual
+elements are perfect, whereas in hybrids they are imperfect.  Even in first
+crosses, the greater or lesser difficulty in effecting a union apparently
+depends on several distinct causes.  There must sometimes be a physical
+impossibility in the male element reaching the ovule, as would be the case
+with a plant having a pistil too long for the pollen-tubes to reach the
+ovarium.  It has also been observed that when pollen of one species is
+placed on the stigma of a distantly allied species, though the pollen-tubes
+protrude, they do not penetrate the stigmatic surface.  Again, the male
+element may reach the female element, but be incapable of causing an embryo
+to be developed, as seems to have been the case with some of Thuret's
+experiments on Fuci.  No explanation can be given of these facts, any more
+than why certain trees cannot be grafted on others.  Lastly, an embryo may
+be developed, and then perish at an early period.  This latter alternative
+has not been sufficiently attended to; but I believe, from observations
+communicated to me by Mr. Hewitt, who has had great experience in
+hybridising gallinaceous birds, that the early death of the embryo is a
+very frequent cause of sterility in first crosses.  I was at first very
+unwilling to believe in this view; as hybrids, when once born, are
+generally healthy and long-lived, as we see in the case of the common mule. 
+Hybrids, however, are differently circumstanced before and after birth: 
+when born and living in a country where their two parents can live, they
+are generally placed under suitable conditions of life.  But a hybrid
+partakes of only half of the nature and constitution of its mother, and
+therefore before birth, as long as it is nourished within its mother's womb
+or within the egg or seed produced by the mother, it may be exposed to
+conditions in some degree unsuitable, and consequently be liable to perish
+at an early period; more especially as all very young beings seem eminently
+sensitive to injurious or unnatural conditions of life.
+</para>
+
+<para>
+In regard to the sterility of hybrids, in which the sexual elements are
+imperfectly developed, the case is very different.  I have more than once
+alluded to a large body of facts, which I have collected, showing that when
+animals and plants are removed from their natural conditions, they are
+extremely liable to have their reproductive systems seriously affected. 
+This, in fact, is the great bar to the domestication of animals.  Between
+the sterility thus superinduced and that of hybrids, there are many points
+of similarity.  In both cases the sterility is independent of general
+health, and is often accompanied by excess of size or great luxuriance.  In
+both cases, the sterility occurs in various degrees; in both, the male
+element is the most liable to be affected; but sometimes the female more
+than the male.  In both, the tendency goes to a certain extent with
+systematic affinity, or whole groups of animals and plants are rendered
+impotent by the same unnatural conditions; and whole groups of species tend
+to produce sterile hybrids.  On the other hand, one species in a group will
+sometimes resist great changes of conditions with unimpaired fertility; and
+certain species in a group will produce unusually fertile hybrids.  No one
+can tell, till he tries, whether any particular animal will breed under
+confinement or any plant seed freely under culture; nor can he tell, till
+he tries, whether any two species of a genus will produce more or less
+sterile hybrids.  Lastly, when organic beings are placed during several
+generations under conditions not natural to them, they are extremely liable
+to vary, which is due, as I believe, to their reproductive systems having
+been specially affected, though in a lesser degree than when sterility
+ensues.  So it is with hybrids, for hybrids in successive generations are
+eminently liable to vary, as every experimentalist has observed.
+</para>
+
+<para>
+Thus we see that when organic beings are placed under new and unnatural
+conditions, and when hybrids are produced by the unnatural crossing of two
+species, the reproductive system, independently of the general state of
+health, is affected by sterility in a very similar manner.  In the one
+case, the conditions of life have been disturbed, though often in so slight
+a degree as to be inappreciable by us; in the other case, or that of
+hybrids,the external conditions have remained the same, but the
+organisation has been disturbed by two different structures and
+constitutions having been blended into one.  For it is scarcely possible
+that two organisations should be compounded into one, without some
+disturbance occurring in the development, or periodical action, or mutual
+relation of the different parts and organs one to another, or to the
+conditions of life.  When hybrids are able to breed inter se, they transmit
+to their offspring from generation to generation the same compounded
+organisation, and hence we need not be surprised that their sterility,
+though in some degree variable, rarely diminishes.
+</para>
+
+<para>
+It must, however, be confessed that we cannot understand, excepting on
+vague hypotheses, several facts with respect to the sterility of hybrids;
+for instance, the unequal fertility of hybrids produced from reciprocal
+crosses; or the increased sterility in those hybrids which occasionally and
+exceptionally resemble closely either pure parent.  Nor do I pretend that
+the foregoing remarks go to the root of the matter:  no explanation is
+offered why an organism, when placed under unnatural conditions, is
+rendered sterile.  All that I have attempted to show, is that in two cases,
+in some respects allied, sterility is the common result,--in the one case
+from the conditions of life having been disturbed, in the other case from
+the organisation having been disturbed by two organisations having been
+compounded into one.
+</para>
+
+<para>
+It may seem fanciful, but I suspect that a similar parallelism extends to
+an allied yet very different class of facts.  It is an old and almost
+universal belief, founded, I think, on a considerable body of evidence,
+that slight changes in the conditions of life are beneficial to all living
+things.  We see this acted on by farmers and gardeners in their frequent
+exchanges of seed, tubers, &amp;c., from one soil or climate to another, and
+back again.  During the convalescence of animals, we plainly see that great
+benefit is derived from almost any change in the habits of life.  Again,
+both with plants and animals, there is abundant evidence, that a cross
+between very distinct individuals of the same species, that is between
+members of different strains or sub-breeds, gives vigour and fertility to
+the offspring.  I believe, indeed, from the facts alluded to in our fourth
+chapter, that a certain amount of crossing is indispensable even with
+hermaphrodites; and that close interbreeding continued during several
+generations between the nearest relations, especially if these be kept
+under the same conditions of life, always induces weakness and sterility in
+the progeny.
+</para>
+
+<para>
+Hence it seems that, on the one hand, slight changes in the conditions of
+life benefit all organic beings, and on the other hand, that slight
+crosses, that is crosses between the males and females of the same species
+which have varied and become slightly different, give vigour and fertility
+to the offspring.  But we have seen that greater changes, or changes of a
+particular nature, often render organic beings in some degree sterile; and
+that greater crosses, that is crosses between males and females which have
+become widely or specifically different, produce hybrids which are
+generally sterile in some degree.  I cannot persuade myself that this
+parallelism is an accident or an illusion.  Both series of facts seem to be
+connected together by some common but unknown bond, which is essentially
+related to the principle of life.
+</para>
+
+<para>
+Fertility of Varieties when crossed, and of their Mongrel off-spring. -- It
+may be urged, as a most forcible argument, that there must be some
+essential distinction between species and varieties, and that there must be
+some error in all the foregoing remarks, inasmuch as varieties, however
+much they may differ from each other in external appearance, cross with
+perfect facility, and yield perfectly fertile offspring.  I fully admit
+that this is almost invariably the case.  But if we look to varieties
+produced under nature, we are immediately involved in hopeless
+difficulties; for if two hitherto reputed varieties be found in any degree
+sterile together, they are at once ranked by most naturalists as species. 
+For instance, the blue and red pimpernel, the primrose and cowslip, which
+are considered by many of our best botanists as varieties, are said by
+Gartner not to be quite fertile when crossed, and he consequently ranks
+them as undoubted species.  If we thus argue in a circle, the fertility of
+all varieties produced under nature will assuredly have to be granted.
+</para>
+
+<para>
+If we turn to varieties, produced, or supposed to have been produced, under
+domestication, we are still involved in doubt.  For when it is stated, for
+instance, that the German Spitz dog unites more easily than other dogs with
+foxes, or that certain South American indigenous domestic dogs do not
+readily cross with European dogs, the explanation which will occur to
+everyone, and probably the true one, is that these dogs have descended from
+several aboriginally distinct species.  Nevertheless the perfect fertility
+of so many domestic varieties, differing widely from each other in
+appearance, for instance of the pigeon or of the cabbage, is a remarkable
+fact; more especially when we reflect how many species there are, which,
+though resembling each other most closely, are utterly sterile when
+intercrossed.  Several considerations, however, render the fertility of
+domestic varieties less remarkable than at first appears.  It can, in the
+first place, be clearly shown that mere external dissimilarity between two
+species does not determine their greater or lesser degree of sterility when
+crossed; and we may apply the same rule to domestic varieties.  In the
+second place, some eminent naturalists believe that a long course of
+domestication tends to eliminate sterility in the successive generations of
+hybrids, which were at first only slightly sterile; and if this be so, we
+surely ought not to expect to find sterility both appearing and
+disappearing under nearly the same conditions of life.  Lastly, and this
+seems to me by far the most important consideration, new races of animals
+and plants are produced under domestication by man's methodical and
+unconscious power of selection, for his own use and pleasure:  he neither
+wishes to select, nor could select, slight differences in the reproductive
+system, or other constitutional differences correlated with the
+reproductive system.  He supplies his several varieties with the same food;
+treats them in nearly the same manner, and does not wish to alter their
+general habits of life.  Nature acts uniformly and slowly during vast
+periods of time on the whole organisation, in any way which may be for each
+creature's own good; and thus she may, either directly, or more probably
+indirectly, through correlation, modify the reproductive system in the
+several descendants from any one species.  Seeing this difference in the
+process of selection, as carried on by man and nature, we need not be
+surprised at some difference in the result.
+</para>
+
+<para>
+I have as yet spoken as if the varieties of the same species were
+invariably fertile when intercrossed.  But it seems to me impossible to
+resist the evidence of the existence of a certain amount of sterility in
+the few following cases, which I will briefly abstract.  The evidence is at
+least as good as that from which we believe in the sterility of a multitude
+of species.  The evidence is, also, derived from hostile witnesses, who in
+all other cases consider fertility and sterility as safe criterions of
+specific distinction.  Gartner kept during several years a dwarf kind of
+maize with yellow seeds, and a tall variety with red seeds, growing near
+each other in his garden; and although these plants have separated sexes,
+they never naturally crossed.  He then fertilised thirteen flowers of the
+one with the pollen of the other; but only a single head produced any seed,
+and this one head produced only five grains.  Manipulation in this case
+could not have been injurious, as the plants have separated sexes.  No one,
+I believe, has suspected that these varieties of maize are distinct
+species; and it is important to notice that the hybrid plants thus raised
+were themselves perfectly fertile; so that even Gartner did not venture to
+consider the two varieties as specifically distinct.
+</para>
+
+<para>
+Girou de Buzareingues crossed three varieties of gourd, which like the
+maize has separated sexes, and he asserts that their mutual fertilisation
+is by so much the less easy as their differences are greater.  How far
+these experiments may be trusted, I know not; but the forms experimentised
+on, are ranked by Sagaret, who mainly founds his classification by the test
+of infertility, as varieties.
+</para>
+
+<para>
+The following case is far more remarkable, and seems at first quite
+incredible; but it is the result of an astonishing number of experiments
+made during many years on nine species of Verbascum, by so good an observer
+and so hostile a witness, as Gartner:  namely, that yellow and white
+varieties of the same species of Verbascum when intercrossed produce less
+seed, than do either coloured varieties when fertilised with pollen from
+their own coloured flowers.  Moreover, he asserts that when yellow and
+white varieties of one species are crossed with yellow and white varieties
+of a distinct species, more seed is produced by the crosses between the
+same coloured flowers, than between those which are differently coloured. 
+Yet these varieties of Verbascum present no other difference besides the
+mere colour of the flower; and one variety can sometimes be raised from the
+seed of the other.
+</para>
+
+<para>
+From observations which I have made on certain varieties of hollyhock, I am
+inclined to suspect that they present analogous facts.
+</para>
+
+<para>
+Kolreuter, whose accuracy has been confirmed by every subsequent observer,
+has proved the remarkable fact, that one variety of the common tobacco is
+more fertile, when crossed with a widely distinct species, than are the
+other varieties.  He experimentised on five forms, which are commonly
+reputed to be varieties, and which he tested by the severest trial, namely,
+by reciprocal crosses, and he found their mongrel offspring perfectly
+fertile.  But one of these five varieties, when used either as father or
+mother, and crossed with the Nicotiana glutinosa, always yielded hybrids
+not so sterile as those which were produced from the four other varieties
+when crossed with N. glutinosa.  Hence the reproductive system of this one
+variety must have been in some manner and in some degree modified.
+</para>
+
+<para>
+From these facts; from the great difficulty of ascertaining the infertility
+of varieties in a state of nature, for a supposed variety if infertile in
+any degree would generally be ranked as species; from man selecting only
+external characters in the production of the most distinct domestic
+varieties, and from not wishing or being able to produce recondite and
+functional differences in the reproductive system; from these several
+considerations and facts, I do not think that the very general fertility of
+varieties can be proved to be of universal occurrence, or to form a
+fundamental distinction between varieties and species.  The general
+fertility of varieties does not seem to me sufficient to overthrow the view
+which I have taken with respect to the very general, but not invariable,
+sterility of first crosses and of hybrids, namely, that it is not a special
+endowment, but is incidental on slowly acquired modifications, more
+especially in the reproductive systems of the forms which are crossed.
+</para>
+
+<para>
+Hybrids and Mongrels compared, independently of their fertility. --
+Independently of the question of fertility, the offspring of species when
+crossed and of varieties when crossed may be compared in several other
+respects.  Gartner, whose strong wish was to draw a marked line of
+distinction between species and varieties, could find very few and, as it
+seems to me, quite unimportant differences between the so-called hybrid
+offspring of species, and the so-called mongrel offspring of varieties. 
+And, on the other hand, they agree most closely in very many important
+respects.
+</para>
+
+<para>
+I shall here discuss this subject with extreme brevity.  The most important
+distinction is, that in the first generation mongrels are more variable
+than hybrids; but Gartner admits that hybrids from species which have long
+been cultivated are often variable in the first generation; and I have
+myself seen striking instances of this fact.  Gartner further admits that
+hybrids between very closely allied species are more variable than those
+from very distinct species; and this shows that the difference in the
+degree of variability graduates away.  When mongrels and the more fertile
+hybrids are propagated for several generations an extreme amount of
+variability in their offspring is notorious; but some few cases both of
+hybrids and mongrels long retaining uniformity of character could be given. 
+The variability, however, in the successive generations of mongrels is,
+perhaps, greater than in hybrids.
+</para>
+
+<para>
+This greater variability of mongrels than of hybrids does not seem to me at
+all surprising.  For the parents of mongrels are varieties, and mostly
+domestic varieties (very few experiments having been tried on natural
+varieties), and this implies in most cases that there has been recent
+variability; and therefore we might expect that such variability would
+often continue and be super-added to that arising from the mere act of
+crossing.  The slight degree of variability in hybrids from the first cross
+or in the first generation, in contrast with their extreme variability in
+the succeeding generations, is a curious fact and deserves attention.  For
+it bears on and corroborates the view which I have taken on the cause of
+ordinary variability; namely, that it is due to the reproductive system
+being eminently sensitive to any change in the conditions of life, being
+thus often rendered either impotent or at least incapable of its proper
+function of producing offspring identical with the parent-form.  Now
+hybrids in the first generation are descended from species (excluding those
+long cultivated) which have not had their reproductive systems in any way
+affected, and they are not variable; but hybrids themselves have their
+reproductive systems seriously affected, and their descendants are highly
+variable.
+</para>
+
+<para>
+But to return to our comparison of mongrels and hybrids:  Gartner states
+that mongrels are more liable than hybrids to revert to either parent-form;
+but this, if it be true, is certainly only a difference in degree.  Gartner
+further insists that when any two species, although most closely allied to
+each other, are crossed with a third species, the hybrids are widely
+different from each other; whereas if two very distinct varieties of one
+species are crossed with another species, the hybrids do not differ much. 
+But this conclusion, as far as I can make out, is founded on a single
+experiment; and seems directly opposed to the results of several
+experiments made by Kolreuter.
+</para>
+
+<para>
+These alone are the unimportant differences, which Gartner is able to point
+out, between hybrid and mongrel plants.  On the other hand, the resemblance
+in mongrels and in hybrids to their respective parents, more especially in
+hybrids produced from nearly related species, follows according to Gartner
+the same laws.  When two species are crossed, one has sometimes a prepotent
+power of impressing its likeness on the hybrid; and so I believe it to be
+with varieties of plants.  With animals one variety certainly often has
+this prepotent power over another variety.  Hybrid plants produced from a
+reciprocal cross, generally resemble each other closely; and so it is with
+mongrels from a reciprocal cross.  Both hybrids and mongrels can be reduced
+to either pure parent-form, by repeated crosses in successive generations
+with either parent.
+</para>
+
+<para>
+These several remarks are apparently applicable to animals; but the subject
+is here excessively complicated, partly owing to the existence of secondary
+sexual characters; but more especially owing to prepotency in transmitting
+likeness running more strongly in one sex than in the other, both when one
+species is crossed with another, and when one variety is crossed with
+another variety.  For instance, I think those authors are right, who
+maintain that the ass has a prepotent power over the horse, so that both
+the mule and the hinny more resemble the ass than the horse; but that the
+prepotency runs more strongly in the male-ass than in the female, so that
+the mule, which is the offspring of the male-ass and mare, is more like an
+ass, than is the hinny, which is the offspring of the female-ass and
+stallion.
+</para>
+
+<para>
+Much stress has been laid by some authors on the supposed fact, that
+mongrel animals alone are born closely like one of their parents; but it
+can be shown that this does sometimes occur with hybrids; yet I grant much
+less frequently with hybrids than with mongrels.  Looking to the cases
+which I have collected of cross-bred animals closely resembling one parent,
+the resemblances seem chiefly confined to characters almost monstrous in
+their nature, and which have suddenly appeared--such as albinism, melanism,
+deficiency of tail or horns, or additional fingers and toes; and do not
+relate to characters which have been slowly acquired by selection. 
+Consequently, sudden reversions to the perfect character of either parent
+would be more likely to occur with mongrels, which are descended from
+varieties often suddenly produced and semi-monstrous in character, than
+with hybrids, which are descended from species slowly and naturally
+produced.  On the whole I entirely agree with Dr. Prosper Lucas, who, after
+arranging an enormous body of facts with respect to animals, comes to the
+conclusion, that the laws of resemblance of the child to its parents are
+the same, whether the two parents differ much or little from each other,
+namely in the union of individuals of the same variety, or of different
+varieties, or of distinct species.
+</para>
+
+<para>
+Laying aside the question of fertility and sterility, in all other respects
+there seems to be a general and close similarity in the offspring of
+crossed species, and of crossed varieties.  If we look at species as having
+been specially created, and at varieties as having been produced by
+secondary laws, this similarity would be an astonishing fact.  But it
+harmonises perfectly with the view that there is no essential distinction
+between species and varieties.
+</para>
+
+<para>
+Summary of Chapter -- First crosses between forms sufficiently distinct to
+be ranked as species, and their hybrids, are very generally, but not
+universally, sterile.  The sterility is of all degrees, and is often so
+slight that the two most careful experimentalists who have ever lived, have
+come to diametrically opposite conclusions in ranking forms by this test. 
+The sterility is innately variable in individuals of the same species, and
+is eminently susceptible of favourable and unfavourable conditions.  The
+degree of sterility does not strictly follow systematic affinity, but is
+governed by several curious and complex laws.  It is generally different,
+and sometimes widely different, in reciprocal crosses between the same two
+species.  It is not always equal in degree in a first cross and in the
+hybrid produced from this cross.
+</para>
+
+<para>
+In the same manner as in grafting trees, the capacity of one species or
+variety to take on another, is incidental on generally unknown differences
+in their vegetative systems, so in crossing, the greater or less facility
+of one species to unite with another, is incidental on unknown differences
+in their reproductive systems.  There is no more reason to think that
+species have been specially endowed with various degrees of sterility to
+prevent them crossing and blending in nature, than to think that trees have
+been specially endowed with various and somewhat analogous degrees of
+difficulty in being grafted together in order to prevent them becoming
+inarched in our forests.
+</para>
+
+<para>
+The sterility of first crosses between pure species, which have their
+reproductive systems perfect, seems to depend on several circumstances; in
+some cases largely on the early death of the embryo.  The sterility of
+hybrids, which have their reproductive systems imperfect, and which have
+had this system and their whole organisation disturbed by being compounded
+of two distinct species, seems closely allied to that sterility which so
+frequently affects pure species, when their natural conditions of life have
+been disturbed.  This view is supported by a parallelism of another
+kind;--namely, that the crossing of forms only slightly different is
+favourable to the vigour and fertility of their offspring; and that slight
+changes in the conditions of life are apparently favourable to the vigour
+and fertility of all organic beings.  It is not surprising that the degree
+of difficulty in uniting two species, and the degree of sterility of their
+hybrid-offspring should generally correspond, though due to distinct
+causes; for both depend on the amount of difference of some kind between
+the species which are crossed.  Nor is it surprising that the facility of
+effecting a first cross, the fertility of the hybrids produced, and the
+capacity of being grafted together--though this latter capacity evidently
+depends on widely different circumstances--should all run, to a certain
+extent, parallel with the systematic affinity of the forms which are
+subjected to experiment; for systematic affinity attempts to express all
+kinds of resemblance between all species.
+</para>
+
+<para>
+First crosses between forms known to be varieties, or sufficiently alike to
+be considered as varieties, and their mongrel offspring, are very
+generally, but not quite universally, fertile.  Nor is this nearly general
+and perfect fertility surprising, when we remember how liable we are to
+argue in a circle with respect to varieties in a state of nature; and when
+we remember that the greater number of varieties have been produced under
+domestication by the selection of mere external differences, and not of
+differences in the reproductive system.  In all other respects, excluding
+fertility, there is a close general resemblance between hybrids and
+mongrels.  Finally, then, the facts briefly given in this chapter do not
+seem to me opposed to, but even rather to support the view, that there is
+no fundamental distinction between species and varieties.
+</para>
+
+</chapter>
+
+<chapter>
+<chapheader>
+
+<chapnum>Chapter IX</chapnum>
+
+<title>On the Imperfection of the Geological Record</title>
+
+<chapsummary>
+On the absence of intermediate varieties at the present day -- On the
+nature of extinct intermediate varieties; on their number -- On the vast
+lapse of time, as inferred from the rate of deposition and of denudation --
+On the poorness of our palaeontological collections -- On the intermittence
+of geological formations -- On the absence of intermediate varieties in any
+one formation -- On the sudden appearance of groups of species -- On their
+sudden appearance in the lowest known fossiliferous strata.
+</chapsummary>
+</chapheader>
+
+<para>
+In the sixth chapter I enumerated the chief objections which might be
+justly urged against the views maintained in this volume.  Most of them
+have now been discussed.  One, namely the distinctness of specific forms,
+and their not being blended together by innumerable transitional links, is
+a very obvious difficulty.  I assigned reasons why such links do not
+commonly occur at the present day, under the circumstances apparently most
+favourable for their presence, namely on an extensive and continuous area
+with graduated physical conditions.  I endeavoured to show, that the life
+of each species depends in a more important manner on the presence of other
+already defined organic forms, than on climate; and, therefore, that the
+really governing conditions of life do not graduate away quite insensibly
+like heat or moisture.  I endeavoured, also, to show that intermediate
+varieties, from existing in lesser numbers than the forms which they
+connect, will generally be beaten out and exterminated during the course of
+further modification and improvement.  The main cause, however, of
+innumerable intermediate links not now occurring everywhere throughout
+nature depends on the very process of natural selection, through which new
+varieties continually take the places of and exterminate their
+parent-forms.  But just in proportion as this process of extermination has
+acted on an enormous scale, so must the number of intermediate varieties,
+which have formerly existed on the earth, be truly enormous.  Why then is
+not every geological formation and every stratum full of such intermediate
+links?  Geology assuredly does not reveal any such finely graduated organic
+chain; and this, perhaps, is the most obvious and gravest objection which
+can be urged against my theory.  The explanation lies, as I believe, in the
+extreme imperfection of the geological record.
+</para>
+
+<para>
+In the first place it should always be borne in mind what sort of
+intermediate forms must, on my theory, have formerly existed.  I have found
+it difficult, when looking at any two species, to avoid picturing to
+myself, forms directly intermediate between them.  But this is a wholly
+false view; we should always look for forms intermediate between each
+species and a common but unknown progenitor; and the progenitor will
+generally have differed in some respects from all its modified descendants. 
+To give a simple illustration:  the fantail and pouter pigeons have both
+descended from the rock-pigeon; if we possessed all the intermediate
+varieties which have ever existed, we should have an extremely close series
+between both and the rock-pigeon; but we should have no varieties directly
+intermediate between the fantail and pouter; none, for instance, combining
+a tail somewhat expanded with a crop somewhat enlarged, the characteristic
+features of these two breeds.  These two breeds, moreover, have become so
+much modified, that if we had no historical or indirect evidence regarding
+their origin, it would not have been possible to have determined from a
+mere comparison of their structure with that of the rock-pigeon, whether
+they had descended from this species or from some other allied species,
+such as C. oenas.
+</para>
+
+<para>
+So with natural species, if we look to forms very distinct, for instance to
+the horse and tapir, we have no reason to suppose that links ever existed
+directly intermediate between them, but between each and an unknown common
+parent.  The common parent will have had in its whole organisation much
+general resemblance to the tapir and to the horse; but in some points of
+structure may have differed considerably from both, even perhaps more than
+they differ from each other.  Hence in all such cases, we should be unable
+to recognise the parent-form of any two or more species, even if we closely
+compared the structure of the parent with that of its modified descendants,
+unless at the same time we had a nearly perfect chain of the intermediate
+links.
+</para>
+
+<para>
+It is just possible by my theory, that one of two living forms might have
+descended from the other; for instance, a horse from a tapir; and in this
+case direct intermediate links will have existed between them.  But such a
+case would imply that one form had remained for a very long period
+unaltered, whilst its descendants had undergone a vast amount of change;
+and the principle of competition between organism and organism, between
+child and parent, will render this a very rare event; for in all cases the
+new and improved forms of life will tend to supplant the old and unimproved
+forms.
+</para>
+
+<para>
+By the theory of natural selection all living species have been connected
+with the parent-species of each genus, by differences not greater than we
+see between the varieties of the same species at the present day; and these
+parent-species, now generally extinct, have in their turn been similarly
+connected with more ancient species; and so on backwards, always converging
+to the common ancestor of each great class.  So that the number of
+intermediate and transitional links, between all living and extinct
+species, must have been inconceivably great.  But assuredly, if this theory
+be true, such have lived upon this earth.
+</para>
+
+<para>
+On the lapse of Time. -- Independently of our not finding fossil remains of
+such infinitely numerous connecting links, it may be objected, that time
+will not have sufficed for so great an amount of organic change, all
+changes having been effected very slowly through natural selection.  It is
+hardly possible for me even to recall to the reader, who may not be a
+practical geologist, the facts leading the mind feebly to comprehend the
+lapse of time.  He who can read Sir Charles Lyell's grand work on the
+Principles of Geology, which the future historian will recognise as having
+produced a revolution in natural science, yet does not admit how
+incomprehensibly vast have been the past periods of time, may at once close
+this volume.  Not that it suffices to study the Principles of Geology, or
+to read special treatises by different observers on separate formations,
+and to mark how each author attempts to give an inadequate idea of the
+duration of each formation or even each stratum.  A man must for years
+examine for himself great piles of superimposed strata, and watch the sea
+at work grinding down old rocks and making fresh sediment, before he can
+hope to comprehend anything of the lapse of time, the monuments of which we
+see around us.
+</para>
+
+<para>
+It is good to wander along lines of sea-coast, when formed of moderately
+hard rocks, and mark the process of degradation.  The tides in most cases
+reach the cliffs only for a short time twice a day, and the waves eat into
+them only when they are charged with sand or pebbles; for there is reason
+to believe that pure water can effect little or nothing in wearing away
+rock.  At last the base of the cliff is undermined, huge fragments fall
+down, and these remaining fixed, have to be worn away, atom by atom, until
+reduced in size they can be rolled about by the waves, and then are more
+quickly ground into pebbles, sand, or mud.  But how often do we see along
+the bases of retreating cliffs rounded boulders, all thickly clothed by
+marine productions, showing how little they are abraded and how seldom they
+are rolled about!  Moreover, if we follow for a few miles any line of rocky
+cliff, which is undergoing degradation, we find that it is only here and
+there, along a short length or round a promontory, that the cliffs are at
+the present time suffering.  The appearance of the surface and the
+vegetation show that elsewhere years have elapsed since the waters washed
+their base.
+</para>
+
+<para>
+He who most closely studies the action of the sea on our shores, will, I
+believe, be most deeply impressed with the slowness with which rocky coasts
+are worn away.  The observations on this head by Hugh Miller, and by that
+excellent observer Mr. Smith of Jordan Hill, are most impressive.  With the
+mind thus impressed, let any one examine beds of conglomerate many thousand
+feet in thickness, which, though probably formed at a quicker rate than
+many other deposits, yet, from being formed of worn and rounded pebbles,
+each of which bears the stamp of time, are good to show how slowly the mass
+has been accumulated.  Let him remember Lyell's profound remark, that the
+thickness and extent of sedimentary formations are the result and measure
+of the degradation which the earth's crust has elsewhere suffered.  And
+what an amount of degradation is implied by the sedimentary deposits of
+many countries!  Professor Ramsay has given me the maximum thickness, in
+most cases from actual measurement, in a few cases from estimate, of each
+formation in different parts of Great Britain; and this is the result:-
+</para>
+
+<list>
+                                                 <item>Feet</item>
+<item>Palaeozoic strata (not including igneous beds)..57,154</item>
+<item>Secondary strata................................13,190</item>
+<item>Tertiary strata..................................2,240</item>
+</list>
+
+<para>
+--making altogether 72,584 feet; that is, very nearly thirteen and
+three-quarters British miles.  Some of these formations, which are
+represented in England by thin beds, are thousands of feet in thickness on
+the Continent.  Moreover, between each successive formation, we have, in
+the opinion of most geologists, enormously long blank periods.  So that the
+lofty pile of sedimentary rocks in Britain, gives but an inadequate idea of
+the time which has elapsed during their accumulation; yet what time this
+must have consumed!  Good observers have estimated that sediment is
+deposited by the great Mississippi river at the rate of only 600 feet in a
+hundred thousand years.  This estimate may be quite erroneous; yet,
+considering over what wide spaces very fine sediment is transported by the
+currents of the sea, the process of accumulation in any one area must be
+extremely slow.
+</para>
+
+<para>
+But the amount of denudation which the strata have in many places suffered,
+independently of the rate of accumulation of the degraded matter, probably
+offers the best evidence of the lapse of time.  I remember having been much
+struck with the evidence of denudation, when viewing volcanic islands,
+which have been worn by the waves and pared all round into perpendicular
+cliffs of one or two thousand feet in height; for the gentle slope of the
+lava-streams, due to their formerly liquid state, showed at a glance how
+far the hard, rocky beds had once extended into the open ocean.  The same
+story is still more plainly told by faults,--those great cracks along which
+the strata have been upheaved on one side, or thrown down on the other, to
+the height or depth of thousands of feet; for since the crust cracked, the
+surface of the land has been so completely planed down by the action of the
+sea, that no trace of these vast dislocations is externally visible.
+</para>
+
+<para>
+The Craven fault, for instance, extends for upwards of 30 miles, and along
+this line the vertical displacement of the strata has varied from 600 to
+3000 feet.  Prof. Ramsay has published an account of a downthrow in
+Anglesea of 2300 feet; and he informs me that he fully believes there is
+one in Merionethshire of 12,000 feet; yet in these cases there is nothing
+on the surface to show such prodigious movements; the pile of rocks on the
+one or other side having been smoothly swept away.  The consideration of
+these facts impresses my mind almost in the same manner as does the vain
+endeavour to grapple with the idea of eternity.
+</para>
+
+<para>
+I am tempted to give one other case, the well-known one of the denudation
+of the Weald.  Though it must be admitted that the denudation of the Weald
+has been a mere trifle, in comparison with that which has removed masses of
+our palaeozoic strata, in parts ten thousand feet in thickness, as shown in
+Prof. Ramsay's masterly memoir on this subject.  Yet it is an admirable
+lesson to stand on the North Downs and to look at the distant South Downs;
+for, remembering that at no great distance to the west the northern and
+southern escarpments meet and close, one can safely picture to oneself the
+great dome of rocks which must have covered up the Weald within so limited
+a period as since the latter part of the Chalk formation.  The distance
+from the northern to the southern Downs is about 22 miles, and the
+thickness of the several formations is on an average about 1100 feet, as I
+am informed by Prof. Ramsay.  But if, as some geologists suppose, a range
+of older rocks underlies the Weald, on the flanks of which the overlying
+sedimentary deposits might have accumulated in thinner masses than
+elsewhere, the above estimate would be erroneous; but this source of doubt
+probably would not greatly affect the estimate as applied to the western
+extremity of the district.  If, then, we knew the rate at which the sea
+commonly wears away a line of cliff of any given height, we could measure
+the time requisite to have denuded the Weald.  This, of course, cannot be
+done; but we may, in order to form some crude notion on the subject, assume
+that the sea would eat into cliffs 500 feet in height at the rate of one
+inch in a century.  This will at first appear much too small an allowance;
+but it is the same as if we were to assume a cliff one yard in height to be
+eaten back along a whole line of coast at the rate of one yard in nearly
+every twenty-two years.  I doubt whether any rock, even as soft as chalk,
+would yield at this rate excepting on the most exposed coasts; though no
+doubt the degradation of a lofty cliff would be more rapid from the
+breakage of the fallen fragments.  On the other hand, I do not believe that
+any line of coast, ten or twenty miles in length, ever suffers degradation
+at the same time along its whole indented length; and we must remember that
+almost all strata contain harder layers or nodules, which from long
+resisting attrition form a breakwater at the base.  Hence, under ordinary
+circumstances, I conclude that for a cliff 500 feet in height, a denudation
+of one inch per century for the whole length would be an ample allowance. 
+At this rate, on the above data, the denudation of the Weald must have
+required 306,662,400 years; or say three hundred million years.
+</para>
+
+<para>
+The action of fresh water on the gently inclined Wealden district, when
+upraised, could hardly have been great, but it would somewhat reduce the
+above estimate.  On the other hand, during oscillations of level, which we
+know this area has undergone, the surface may have existed for millions of
+years as land, and thus have escaped the action of the sea:  when deeply
+submerged for perhaps equally long periods, it would, likewise, have
+escaped the action of the coast-waves.  So that in all probability a far
+longer period than 300 million years has elapsed since the latter part of
+the Secondary period.
+</para>
+
+<para>
+I have made these few remarks because it is highly important for us to gain
+some notion, however imperfect, of the lapse of years.  During each of
+these years, over the whole world, the land and the water has been peopled
+by hosts of living forms.  What an infinite number of generations, which
+the mind cannot grasp, must have succeeded each other in the long roll of
+years!  Now turn to our richest geological museums, and what a paltry
+display we behold!
+</para>
+
+<para>
+On the poorness of our Palaeontological collections. -- That our
+palaeontological collections are very imperfect, is admitted by every one. 
+The remark of that admirable palaeontologist, the late Edward Forbes,
+should not be forgotten, namely, that numbers of our fossil species are
+known and named from single and often broken specimens, or from a few
+specimens collected on some one spot.  Only a small portion of the surface
+of the earth has been geologically explored, and no part with sufficient
+care, as the important discoveries made every year in Europe prove.  No
+organism wholly soft can be preserved.  Shells and bones will decay and
+disappear when left on the bottom of the sea, where sediment is not
+accumulating.  I believe we are continually taking a most erroneous view,
+when we tacitly admit to ourselves that sediment is being deposited over
+nearly the whole bed of the sea, at a rate sufficiently quick to embed and
+preserve fossil remains.  Throughout an enormously large proportion of the
+ocean, the bright blue tint of the water bespeaks its purity.  The many
+cases on record of a formation conformably covered, after an enormous
+interval of time, by another and later formation, without the underlying
+bed having suffered in the interval any wear and tear, seem explicable only
+on the view of the bottom of the sea not rarely lying for ages in an
+unaltered condition.  The remains which do become embedded, if in sand or
+gravel, will when the beds are upraised generally be dissolved by the
+percolation of rain-water.  I suspect that but few of the very many animals
+which live on the beach between high and low watermark are preserved.  For
+instance, the several species of the Chthamalinae (a sub-family of sessile
+cirripedes) coat the rocks all over the world in infinite numbers:  they
+are all strictly littoral, with the exception of a single Mediterranean
+species, which inhabits deep water and has been found fossil in Sicily,
+whereas not one other species has hitherto been found in any tertiary
+formation:  yet it is now known that the genus Chthamalus existed during
+the chalk period.  The molluscan genus Chiton offers a partially analogous
+case.
+</para>
+
+<para>
+With respect to the terrestrial productions which lived during the
+Secondary and Palaeozoic periods, it is superfluous to state that our
+evidence from fossil remains is fragmentary in an extreme degree.  For
+instance, not a land shell is known belonging to either of these vast
+periods, with one exception discovered by Sir C. Lyell in the carboniferous
+strata of North America.  In regard to mammiferous remains, a single glance
+at the historical table published in the Supplement to Lyell's Manual, will
+bring home the truth, how accidental and rare is their preservation, far
+better than pages of detail.  Nor is their rarity surprising, when we
+remember how large a proportion of the bones of tertiary mammals have been
+discovered either in caves or in lacustrine deposits; and that not a cave
+or true lacustrine bed is known belonging to the age of our secondary or
+palaeozoic formations.
+</para>
+
+<para>
+But the imperfection in the geological record mainly results from another
+and more important cause than any of the foregoing; namely, from the
+several formations being separated from each other by wide intervals of
+time.  When we see the formations tabulated in written works, or when we
+follow them in nature, it is difficult to avoid believing that they are
+closely consecutive.  But we know, for instance, from Sir R. Murchison's
+great work on Russia, what wide gaps there are in that country between the
+superimposed formations; so it is in North America, and in many other parts
+of the world.  The most skilful geologist, if his attention had been
+exclusively confined to these large territories, would never have suspected
+that during the periods which were blank and barren in his own country,
+great piles of sediment, charged with new and peculiar forms of life, had
+elsewhere been accumulated.  And if in each separate territory, hardly any
+idea can be formed of the length of time which has elapsed between the
+consecutive formations, we may infer that this could nowhere be
+ascertained.  The frequent and great changes in the mineralogical
+composition of consecutive formations, generally implying great changes in
+the geography of the surrounding lands, whence the sediment has been
+derived, accords with the belief of vast intervals of time having elapsed
+between each formation.
+</para>
+
+<para>
+But we can, I think, see why the geological formations of each region are
+almost invariably intermittent; that is, have not followed each other in
+close sequence.  Scarcely any fact struck me more when examining many
+hundred miles of the South American coasts, which have been upraised
+several hundred feet within the recent period, than the absence of any
+recent deposits sufficiently extensive to last for even a short geological
+period.  Along the whole west coast, which is inhabited by a peculiar
+marine fauna, tertiary beds are so scantily developed, that no record of
+several successive and peculiar marine faunas will probably be preserved to
+a distant age.  A little reflection will explain why along the rising coast
+of the western side of South America, no extensive formations with recent
+or tertiary remains can anywhere be found, though the supply of sediment
+must for ages have been great, from the enormous degradation of the
+coast-rocks and from muddy streams entering the sea.  The explanation, no
+doubt, is, that the littoral and sub-littoral deposits are continually worn
+away, as soon as they are brought up by the slow and gradual rising of the
+land within the grinding action of the coast-waves.
+</para>
+
+<para>
+We may, I think, safely conclude that sediment must be accumulated in
+extremely thick, solid, or extensive masses, in order to withstand the
+incessant action of the waves, when first upraised and during subsequent
+oscillations of level.  Such thick and extensive accumulations of sediment
+may be formed in two ways; either, in profound depths of the sea, in which
+case, judging from the researches of E. Forbes, we may conclude that the
+bottom will be inhabited by extremely few animals, and the mass when
+upraised will give a most imperfect record of the forms of life which then
+existed; or, sediment may be accumulated to any thickness and extent over a
+shallow bottom, if it continue slowly to subside.  In this latter case, as
+long as the rate of subsidence and supply of sediment nearly balance each
+other, the sea will remain shallow and favourable for life, and thus a
+fossiliferous formation thick enough, when upraised, to resist any amount
+of degradation, may be formed.
+</para>
+
+<para>
+I am convinced that all our ancient formations, which are rich in fossils,
+have thus been formed during subsidence.  Since publishing my views on this
+subject in 1845, I have watched the progress of Geology, and have been
+surprised to note how author after author, in treating of this or that
+great formation, has come to the conclusion that it was accumulated during
+subsidence.  I may add, that the only ancient tertiary formation on the
+west coast of South America, which has been bulky enough to resist such
+degradation as it has as yet suffered, but which will hardly last to a
+distant geological age, was certainly deposited during a downward
+oscillation of level, and thus gained considerable thickness.
+</para>
+
+<para>
+All geological facts tell us plainly that each area has undergone numerous
+slow oscillations of level, and apparently these oscillations have affected
+wide spaces.  Consequently formations rich in fossils and sufficiently
+thick and extensive to resist subsequent degradation, may have been formed
+over wide spaces during periods of subsidence, but only where the supply of
+sediment was sufficient to keep the sea shallow and to embed and preserve
+the remains before they had time to decay.  On the other hand, as long as
+the bed of the sea remained stationary, thick deposits could not have been
+accumulated in the shallow parts, which are the most favourable to life. 
+Still less could this have happened during the alternate periods of
+elevation; or, to speak more accurately, the beds which were then
+accumulated will have been destroyed by being upraised and brought within
+the limits of the coast-action.
+</para>
+
+<para>
+Thus the geological record will almost necessarily be rendered
+intermittent.  I feel much confidence in the truth of these views, for they
+are in strict accordance with the general principles inculcated by Sir C.
+Lyell; and E. Forbes independently arrived at a similar conclusion.
+</para>
+
+<para>
+One remark is here worth a passing notice.  During periods of elevation the
+area of the land and of the adjoining shoal parts of the sea will be
+increased, and new stations will often be formed;--all circumstances most
+favourable, as previously explained, for the formation of new varieties and
+species; but during such periods there will generally be a blank in the
+geological record.  On the other hand, during subsidence, the inhabited
+area and number of inhabitants will decrease (excepting the productions on
+the shores of a continent when first broken up into an archipelago), and
+consequently during subsidence, though there will be much extinction, fewer
+new varieties or species will be formed; and it is during these very
+periods of subsidence, that our great deposits rich in fossils have been
+accumulated.  Nature may almost be said to have guarded against the
+frequent discovery of her transitional or linking forms.
+</para>
+
+<para>
+From the foregoing considerations it cannot be doubted that the geological
+record, viewed as a whole, is extremely imperfect; but if we confine our
+attention to any one formation, it becomes more difficult to understand,
+why we do not therein find closely graduated varieties between the allied
+species which lived at its commencement and at its close.  Some cases are
+on record of the same species presenting distinct varieties in the upper
+and lower parts of the same formation, but, as they are rare, they may be
+here passed over.  Although each formation has indisputably required a vast
+number of years for its deposition, I can see several reasons why each
+should not include a graduated series of links between the species which
+then lived; but I can by no means pretend to assign due proportional weight
+to the following considerations.
+</para>
+
+<para>
+Although each formation may mark a very long lapse of years, each perhaps
+is short compared with the period requisite to change one species into
+another.  I am aware that two palaeontologists, whose opinions are worthy
+of much deference, namely Bronn and Woodward, have concluded that the
+average duration of each formation is twice or thrice as long as the
+average duration of specific forms.  But insuperable difficulties, as it
+seems to me, prevent us coming to any just conclusion on this head.  When
+we see a species first appearing in the middle of any formation, it would
+be rash in the extreme to infer that it had not elsewhere previously
+existed.  So again when we find a species disappearing before the uppermost
+layers have been deposited, it would be equally rash to suppose that it
+then became wholly extinct.  We forget how small the area of Europe is
+compared with the rest of the world; nor have the several stages of the
+same formation throughout Europe been correlated with perfect accuracy.
+</para>
+
+<para>
+With marine animals of all kinds, we may safely infer a large amount of
+migration during climatal and other changes; and when we see a species
+first appearing in any formation, the probability is that it only then
+first immigrated into that area.  It is well known, for instance, that
+several species appeared somewhat earlier in the palaeozoic beds of North
+America than in those of Europe; time having apparently been required for
+their migration from the American to the European seas.  In examining the
+latest deposits of various quarters of the world, it has everywhere been
+noted, that some few still existing species are common in the deposit, but
+have become extinct in the immediately surrounding sea; or, conversely,
+that some are now abundant in the neighbouring sea, but are rare or absent
+in this particular deposit.  It is an excellent lesson to reflect on the
+ascertained amount of migration of the inhabitants of Europe during the
+Glacial period, which forms only a part of one whole geological period; and
+likewise to reflect on the great changes of level, on the inordinately
+great change of climate, on the prodigious lapse of time, all included
+within this same glacial period.  Yet it may be doubted whether in any
+quarter of the world, sedimentary deposits, including fossil remains, have
+gone on accumulating within the same area during the whole of this period. 
+It is not, for instance, probable that sediment was deposited during the
+whole of the glacial period near the mouth of the Mississippi, within that
+limit of depth at which marine animals can flourish; for we know what vast
+geographical changes occurred in other parts of America during this space
+of time.  When such beds as were deposited in shallow water near the mouth
+of the Mississippi during some part of the glacial period shall have been
+upraised, organic remains will probably first appear and disappear at
+different levels, owing to the migration of species and to geographical
+changes.  And in the distant future, a geologist examining these beds,
+might be tempted to conclude that the average duration of life of the
+embedded fossils had been less than that of the glacial period, instead of
+having been really far greater, that is extending from before the glacial
+epoch to the present day.
+</para>
+
+<para>
+In order to get a perfect gradation between two forms in the upper and
+lower parts of the same formation, the deposit must have gone on
+accumulating for a very long period, in order to have given sufficient time
+for the slow process of variation; hence the deposit will generally have to
+be a very thick one; and the species undergoing modification will have had
+to live on the same area throughout this whole time.  But we have seen that
+a thick fossiliferous formation can only be accumulated during a period of
+subsidence; and to keep the depth approximately the same, which is
+necessary in order to enable the same species to live on the same space,
+the supply of sediment must nearly have counterbalanced the amount of
+subsidence.  But this same movement of subsidence will often tend to sink
+the area whence the sediment is derived, and thus diminish the supply
+whilst the downward movement continues.  In fact, this nearly exact
+balancing between the supply of sediment and the amount of subsidence is
+probably a rare contingency; for it has been observed by more than one
+palaeontologist, that very thick deposits are usually barren of organic
+remains, except near their upper or lower limits.
+</para>
+
+<para>
+It would seem that each separate formation, like the whole pile of
+formations in any country, has generally been intermittent in its
+accumulation.  When we see, as is so often the case, a formation composed
+of beds of different mineralogical composition, we may reasonably suspect
+that the process of deposition has been much interrupted, as a change in
+the currents of the sea and a supply of sediment of a different nature will
+generally have been due to geographical changes requiring much time.  Nor
+will the closest inspection of a formation give any idea of the time which
+its deposition has consumed.  Many instances could be given of beds only a
+few feet in thickness, representing formations, elsewhere thousands of feet
+in thickness, and which must have required an enormous period for their
+accumulation; yet no one ignorant of this fact would have suspected the
+vast lapse of time represented by the thinner formation.  Many cases could
+be given of the lower beds of a formation having been upraised, denuded,
+submerged, and then re-covered by the upper beds of the same
+formation,--facts, showing what wide, yet easily overlooked, intervals have
+occurred in its accumulation.  In other cases we have the plainest evidence
+in great fossilised trees, still standing upright as they grew, of many
+long intervals of time and changes of level during the process of
+deposition, which would never even have been suspected, had not the trees
+chanced to have been preserved:  thus, Messrs. Lyell and Dawson found
+carboniferous beds 1400 feet thick in Nova Scotia, with ancient
+root-bearing strata, one above the other, at no less than sixty-eight
+different levels.  Hence, when the same species occur at the bottom,
+middle, and top of a formation, the probability is that they have not lived
+on the same spot during the whole period of deposition, but have
+disappeared and reappeared, perhaps many times, during the same geological
+period.  So that if such species were to undergo a considerable amount of
+modification during any one geological period, a section would not probably
+include all the fine intermediate gradations which must on my theory have
+existed between them, but abrupt, though perhaps very slight, changes of
+form.
+</para>
+
+<para>
+It is all-important to remember that naturalists have no golden rule by
+which to distinguish species and varieties; they grant some little
+variability to each species, but when they meet with a somewhat greater
+amount of difference between any two forms, they rank both as species,
+unless they are enabled to connect them together by close intermediate
+gradations.  And this from the reasons just assigned we can seldom hope to
+effect in any one geological section.  Supposing B and C to be two species,
+and a third, A, to be found in an underlying bed; even if A were strictly
+intermediate between B and C, it would simply be ranked as a third and
+distinct species, unless at the same time it could be most closely
+connected with either one or both forms by intermediate varieties.  Nor
+should it be forgotten, as before explained, that A might be the actual
+progenitor of B and C, and yet might not at all necessarily be strictly
+intermediate between them in all points of structure.  So that we might
+obtain the parent-species and its several modified descendants from the
+lower and upper beds of a formation, and unless we obtained numerous
+transitional gradations, we should not recognise their relationship, and
+should consequently be compelled to rank them all as distinct species.
+</para>
+
+<para>
+It is notorious on what excessively slight differences many
+palaeontologists have founded their species; and they do this the more
+readily if the specimens come from different sub-stages of the same
+formation.  Some experienced conchologists are now sinking many of the very
+fine species of D'Orbigny and others into the rank of varieties; and on
+this view we do find the kind of evidence of change which on my theory we
+ought to find.  Moreover, if we look to rather wider intervals, namely, to
+distinct but consecutive stages of the same great formation, we find that
+the embedded fossils, though almost universally ranked as specifically
+different, yet are far more closely allied to each other than are the
+species found in more widely separated formations; but to this subject I
+shall have to return in the following chapter.
+</para>
+
+<para>
+One other consideration is worth notice:  with animals and plants that can
+propagate rapidly and are not highly locomotive, there is reason to
+suspect, as we have formerly seen, that their varieties are generally at
+first local; and that such local varieties do not spread widely and
+supplant their parent-forms until they have been modified and perfected in
+some considerable degree.  According to this view, the chance of
+discovering in a formation in any one country all the early stages of
+transition between any two forms, is small, for the successive changes are
+supposed to have been local or confined to some one spot.  Most marine
+animals have a wide range; and we have seen that with plants it is those
+which have the widest range, that oftenest present varieties; so that with
+shells and other marine animals, it is probably those which have had the
+widest range, far exceeding the limits of the known geological formations
+of Europe, which have oftenest given rise, first to local varieties and
+ultimately to new species; and this again would greatly lessen the chance
+of our being able to trace the stages of transition in any one geological
+formation.
+</para>
+
+<para>
+It should not be forgotten, that at the present day, with perfect specimens
+for examination, two forms can seldom be connected by intermediate
+varieties and thus proved to be the same species, until many specimens have
+been collected from many places; and in the case of fossil species this
+could rarely be effected by palaeontologists.  We shall, perhaps, best
+perceive the improbability of our being enabled to connect species by
+numerous, fine, intermediate, fossil links, by asking ourselves whether,
+for instance, geologists at some future period will be able to prove, that
+our different breeds of cattle, sheep, horses, and dogs have descended from
+a single stock or from several aboriginal stocks; or, again, whether
+certain sea-shells inhabiting the shores of North America, which are ranked
+by some conchologists as distinct species from their European
+representatives, and by other conchologists as only varieties, are really
+varieties or are, as it is called, specifically distinct.  This could be
+effected only by the future geologist discovering in a fossil state
+numerous intermediate gradations; and such success seems to me improbable
+in the highest degree.
+</para>
+
+<para>
+Geological research, though it has added numerous species to existing and
+extinct genera, and has made the intervals between some few groups less
+wide than they otherwise would have been, yet has done scarcely anything in
+breaking down the distinction between species, by connecting them together
+by numerous, fine, intermediate varieties; and this not having been
+effected, is probably the gravest and most obvious of all the many
+objections which may be urged against my views.  Hence it will be worth
+while to sum up the foregoing remarks, under an imaginary illustration. 
+The Malay Archipelago is of about the size of Europe from the North Cape to
+the Mediterranean, and from Britain to Russia; and therefore equals all the
+geological formations which have been examined with any accuracy, excepting
+those of the United States of America.  I fully agree with Mr.
+Godwin-Austen, that the present condition of the Malay Archipelago, with
+its numerous large islands separated by wide and shallow seas, probably
+represents the former state of Europe, when most of our formations were
+accumulating.  The Malay Archipelago is one of the richest regions of the
+whole world in organic beings; yet if all the species were to be collected
+which have ever lived there, how imperfectly would they represent the
+natural history of the world!
+</para>
+
+<para>
+But we have every reason to believe that the terrestrial productions of the
+archipelago would be preserved in an excessively imperfect manner in the
+formations which we suppose to be there accumulating.  I suspect that not
+many of the strictly littoral animals, or of those which lived on naked
+submarine rocks, would be embedded; and those embedded in gravel or sand,
+would not endure to a distant epoch.  Wherever sediment did not accumulate
+on the bed of the sea, or where it did not accumulate at a sufficient rate
+to protect organic bodies from decay, no remains could be preserved.
+</para>
+
+<para>
+In our archipelago, I believe that fossiliferous formations could be formed
+of sufficient thickness to last to an age, as distant in futurity as the
+secondary formations lie in the past, only during periods of subsidence. 
+These periods of subsidence would be separated from each other by enormous
+intervals, during which the area would be either stationary or rising;
+whilst rising, each fossiliferous formation would be destroyed, almost as
+soon as accumulated, by the incessant coast-action, as we now see on the
+shores of South America.  During the periods of subsidence there would
+probably be much extinction of life; during the periods of elevation, there
+would be much variation, but the geological record would then be least
+perfect.
+</para>
+
+<para>
+It may be doubted whether the duration of any one great period of
+subsidence over the whole or part of the archipelago, together with a
+contemporaneous accumulation of sediment, would exceed the average duration
+of the same specific forms; and these contingencies are indispensable for
+the preservation of all the transitional gradations between any two or more
+species.  If such gradations were not fully preserved, transitional
+varieties would merely appear as so many distinct species.  It is, also,
+probable that each great period of subsidence would be interrupted by
+oscillations of level, and that slight climatal changes would intervene
+during such lengthy periods; and in these cases the inhabitants of the
+archipelago would have to migrate, and no closely consecutive record of
+their modifications could be preserved in any one formation.
+</para>
+
+<para>
+Very many of the marine inhabitants of the archipelago now range thousands
+of miles beyond its confines; and analogy leads me to believe that it would
+be chiefly these far-ranging species which would oftenest produce new
+varieties; and the varieties would at first generally be local or confined
+to one place, but if possessed of any decided advantage, or when further
+modified and improved, they would slowly spread and supplant their
+parent-forms.  When such varieties returned to their ancient homes, as they
+would differ from their former state, in a nearly uniform, though perhaps
+extremely slight degree, they would, according to the principles followed
+by many palaeontologists, be ranked as new and distinct species.
+</para>
+
+<para>
+If then, there be some degree of truth in these remarks, we have no right
+to expect to find in our geological formations, an infinite number of those
+fine transitional forms, which on my theory assuredly have connected all
+the past and present species of the same group into one long and branching
+chain of life.  We ought only to look for a few links, some more closely,
+some more distantly related to each other; and these links, let them be
+ever so close, if found in different stages of the same formation, would,
+by most palaeontologists, be ranked as distinct species.  But I do not
+pretend that I should ever have suspected how poor a record of the
+mutations of life, the best preserved geological section presented, had not
+the difficulty of our not discovering innumerable transitional links
+between the species which appeared at the commencement and close of each
+formation, pressed so hardly on my theory.
+</para>
+
+<para>
+On the sudden appearance of whole groups of Allied Species. -- The abrupt
+manner in which whole groups of species suddenly appear in certain
+formations, has been urged by several palaeontologists, for instance, by
+Agassiz, Pictet, and by none more forcibly than by Professor Sedgwick, as a
+fatal objection to the belief in the transmutation of species.  If numerous
+species, belonging to the same genera or families, have really started into
+life all at once, the fact would be fatal to the theory of descent with
+slow modification through natural selection.  For the development of a
+group of forms, all of which have descended from some one progenitor, must
+have been an extremely slow process; and the progenitors must have lived
+long ages before their modified descendants.  But we continually over-rate
+the perfection of the geological record, and falsely infer, because certain
+genera or families have not been found beneath a certain stage, that they
+did not exist before that stage.  We continually forget how large the world
+is, compared with the area over which our geological formations have been
+carefully examined; we forget that groups of species may elsewhere have
+long existed and have slowly multiplied before they invaded the ancient
+archipelagoes of Europe and of the United States.  We do not make due
+allowance for the enormous intervals of time, which have probably elapsed
+between our consecutive formations,--longer perhaps in some cases than the
+time required for the accumulation of each formation.  These intervals will
+have given time for the multiplication of species from some one or some few
+parent-forms; and in the succeeding formation such species will appear as
+if suddenly created.
+</para>
+
+<para>
+I may here recall a remark formerly made, namely that it might require a
+long succession of ages to adapt an organism to some new and peculiar line
+of life, for instance to fly through the air; but that when this had been
+effected, and a few species had thus acquired a great advantage over other
+organisms, a comparatively short time would be necessary to produce many
+divergent forms, which would be able to spread rapidly and widely
+throughout the world.
+</para>
+
+<para>
+I will now give a few examples to illustrate these remarks; and to show how
+liable we are to error in supposing that whole groups of species have
+suddenly been produced.  I may recall the well-known fact that in
+geological treatises, published not many years ago, the great class of
+mammals was always spoken of as having abruptly come in at the commencement
+of the tertiary series.  And now one of the richest known accumulations of
+fossil mammals belongs to the middle of the secondary series; and one true
+mammal has been discovered in the new red sandstone at nearly the
+commencement of this great series.  Cuvier used to urge that no monkey
+occurred in any tertiary stratum; but now extinct species have been
+discovered in India, South America, and in Europe even as far back as the
+eocene stage.  The most striking case, however, is that of the Whale
+family; as these animals have huge bones, are marine, and range over the
+world, the fact of not a single bone of a whale having been discovered in
+any secondary formation, seemed fully to justify the belief that this great
+and distinct order had been suddenly produced in the interval between the
+latest secondary and earliest tertiary formation.  But now we may read in
+the Supplement to Lyell's 'Manual,' published in 1858, clear evidence of
+the existence of whales in the upper greensand, some time before the close
+of the secondary period.
+</para>
+
+<para>
+I may give another instance, which from having passed under my own eyes has
+much struck me.  In a memoir on Fossil Sessile Cirripedes, I have stated
+that, from the number of existing and extinct tertiary species; from the
+extraordinary abundance of the individuals of many species all over the
+world, from the Arctic regions to the equator, inhabiting various zones of
+depths from the upper tidal limits to 50 fathoms; from the perfect manner
+in which specimens are preserved in the oldest tertiary beds; from the ease
+with which even a fragment of a valve can be recognised; from all these
+circumstances, I inferred that had sessile cirripedes existed during the
+secondary periods, they would certainly have been preserved and discovered;
+and as not one species had been discovered in beds of this age, I concluded
+that this great group had been suddenly developed at the commencement of
+the tertiary series.  This was a sore trouble to me, adding as I thought
+one more instance of the abrupt appearance of a great group of species. 
+But my work had hardly been published, when a skilful palaeontologist, M.
+Bosquet, sent me a drawing of a perfect specimen of an unmistakeable
+sessile cirripede, which he had himself extracted from the chalk of
+Belgium.  And, as if to make the case as striking as possible, this sessile
+cirripede was a Chthamalus, a very common, large, and ubiquitous genus, of
+which not one specimen has as yet been found even in any tertiary stratum. 
+Hence we now positively know that sessile cirripedes existed during the
+secondary period; and these cirripedes might have been the progenitors of
+our many tertiary and existing species.
+</para>
+
+<para>
+The case most frequently insisted on by palaeontologists of the apparently
+sudden appearance of a whole group of species, is that of the teleostean
+fishes, low down in the Chalk period.  This group includes the large
+majority of existing species.  Lately, Professor Pictet has carried their
+existence one sub-stage further back; and some palaeontologists believe
+that certain much older fishes, of which the affinities are as yet
+imperfectly known, are really teleostean.  Assuming, however, that the
+whole of them did appear, as Agassiz believes, at the commencement of the
+chalk formation, the fact would certainly be highly remarkable; but I
+cannot see that it would be an insuperable difficulty on my theory, unless
+it could likewise be shown that the species of this group appeared suddenly
+and simultaneously throughout the world at this same period.  It is almost
+superfluous to remark that hardly any fossil-fish are known from south of
+the equator; and by running through Pictet's Palaeontology it will be seen
+that very few species are known from several formations in Europe.  Some
+few families of fish now have a confined range; the teleostean fish might
+formerly have had a similarly confined range, and after having been largely
+developed in some one sea, might have spread widely.  Nor have we any right
+to suppose that the seas of the world have always been so freely open from
+south to north as they are at present.  Even at this day, if the Malay
+Archipelago were converted into land, the tropical parts of the Indian
+Ocean would form a large and perfectly enclosed basin, in which any great
+group of marine animals might be multiplied; and here they would remain
+confined, until some of the species became adapted to a cooler climate, and
+were enabled to double the southern capes of Africa or Australia, and thus
+reach other and distant seas.
+</para>
+
+<para>
+From these and similar considerations, but chiefly from our ignorance of
+the geology of other countries beyond the confines of Europe and the United
+States; and from the revolution in our palaeontological ideas on many
+points, which the discoveries of even the last dozen years have effected,
+it seems to me to be about as rash in us to dogmatize on the succession of
+organic beings throughout the world, as it would be for a naturalist to
+land for five minutes on some one barren point in Australia, and then to
+discuss the number and range of its productions.
+</para>
+
+<para>
+On the sudden appearance of groups of Allied Species in the lowest known
+fossiliferous strata. -- There is another and allied difficulty, which is
+much graver.  I allude to the manner in which numbers of species of the
+same group, suddenly appear in the lowest known fossiliferous rocks.  Most
+of the arguments which have convinced me that all the existing species of
+the same group have descended from one progenitor, apply with nearly equal
+force to the earliest known species.  For instance, I cannot doubt that all
+the Silurian trilobites have descended from some one crustacean, which must
+have lived long before the Silurian age, and which probably differed
+greatly from any known animal.  Some of the most ancient Silurian animals,
+as the Nautilus, Lingula, &amp;c., do not differ much from living species; and
+it cannot on my theory be supposed, that these old species were the
+progenitors of all the species of the orders to which they belong, for they
+do not present characters in any degree intermediate between them.  If,
+moreover, they had been the progenitors of these orders, they would almost
+certainly have been long ago supplanted and exterminated by their numerous
+and improved descendants.
+</para>
+
+<para>
+Consequently, if my theory be true, it is indisputable that before the
+lowest Silurian stratum was deposited, long periods elapsed, as long as, or
+probably far longer than, the whole interval from the Silurian age to the
+present day; and that during these vast, yet quite unknown, periods of
+time, the world swarmed with living creatures.
+</para>
+
+<para>
+To the question why we do not find records of these vast primordial
+periods, I can give no satisfactory answer.  Several of the most eminent
+geologists, with Sir R. Murchison at their head, are convinced that we see
+in the organic remains of the lowest Silurian stratum the dawn of life on
+this planet.  Other highly competent judges, as Lyell and the late E.
+Forbes, dispute this conclusion.  We should not forget that only a small
+portion of the world is known with accuracy.  M. Barrande has lately added
+another and lower stage to the Silurian system, abounding with new and
+peculiar species.  Traces of life have been detected in the Longmynd beds
+beneath Barrande's so-called primordial zone.  The presence of phosphatic
+nodules and bituminous matter in some of the lowest azoic rocks, probably
+indicates the former existence of life at these periods.  But the
+difficulty of understanding the absence of vast piles of fossiliferous
+strata, which on my theory no doubt were somewhere accumulated before the
+Silurian epoch, is very great.  If these most ancient beds had been wholly
+worn away by denudation, or obliterated by metamorphic action, we ought to
+find only small remnants of the formations next succeeding them in age, and
+these ought to be very generally in a metamorphosed condition.  But the
+descriptions which we now possess of the Silurian deposits over immense
+territories in Russia and in North America, do not support the view, that
+the older a formation is, the more it has suffered the extremity of
+denudation and metamorphism.
+</para>
+
+<para>
+The case at present must remain inexplicable; and may be truly urged as a
+valid argument against the views here entertained.  To show that it may
+hereafter receive some explanation, I will give the following hypothesis. 
+From the nature of the organic remains, which do not appear to have
+inhabited profound depths, in the several formations of Europe and of the
+United States; and from the amount of sediment, miles in thickness, of
+which the formations are composed, we may infer that from first to last
+large islands or tracts of land, whence the sediment was derived, occurred
+in the neighbourhood of the existing continents of Europe and North
+America.  But we do not know what was the state of things in the intervals
+between the successive formations; whether Europe and the United States
+during these intervals existed as dry land, or as a submarine surface near
+land, on which sediment was not deposited, or again as the bed of an open
+and unfathomable sea.
+</para>
+
+<para>
+Looking to the existing oceans, which are thrice as extensive as the land,
+we see them studded with many islands; but not one oceanic island is as yet
+known to afford even a remnant of any palaeozoic or secondary formation. 
+Hence we may perhaps infer, that during the palaeozoic and secondary
+periods, neither continents nor continental islands existed where our
+oceans now extend; for had they existed there, palaeozoic and secondary
+formations would in all probability have been accumulated from sediment
+derived from their wear and tear; and would have been at least partially
+upheaved by the oscillations of level, which we may fairly conclude must
+have intervened during these enormously long periods.  If then we may infer
+anything from these facts, we may infer that where our oceans now extend,
+oceans have extended from the remotest period of which we have any record;
+and on the other hand, that where continents now exist, large tracts of
+land have existed, subjected no doubt to great oscillations of level, since
+the earliest silurian period.  The coloured map appended to my volume on
+Coral Reefs, led me to conclude that the great oceans are still mainly
+areas of subsidence, the great archipelagoes still areas of oscillations of
+level, and the continents areas of elevation.  But have we any right to
+assume that things have thus remained from eternity?  Our continents seem
+to have been formed by a preponderance, during many oscillations of level,
+of the force of elevation; but may not the areas of preponderant movement
+have changed in the lapse of ages?  At a period immeasurably antecedent to
+the silurian epoch, continents may have existed where oceans are now spread
+out; and clear and open oceans may have existed where our continents now
+stand.  Nor should we be justified in assuming that if, for instance, the
+bed of the Pacific Ocean were now converted into a continent, we should
+there find formations older than the silurian strata, supposing such to
+have been formerly deposited; for it might well happen that strata which
+had subsided some miles nearer to the centre of the earth, and which had
+been pressed on by an enormous weight of superincumbent water, might have
+undergone far more metamorphic action than strata which have always
+remained nearer to the surface.  The immense areas in some parts of the
+world, for instance in South America, of bare metamorphic rocks, which must
+have been heated under great pressure, have always seemed to me to require
+some special explanation; and we may perhaps believe that we see in these
+large areas, the many formations long anterior to the silurian epoch in a
+completely metamorphosed condition.
+</para>
+
+<para>
+The several difficulties here discussed, namely our not finding in the
+successive formations infinitely numerous transitional links between the
+many species which now exist or have existed; the sudden manner in which
+whole groups of species appear in our European formations; the almost
+entire absence, as at present known, of fossiliferous formations beneath
+the Silurian strata, are all undoubtedly of the gravest nature.  We see
+this in the plainest manner by the fact that all the most eminent
+palaeontologists, namely Cuvier, Owen, Agassiz, Barrande, Falconer, E.
+Forbes, &amp;c., and all our greatest geologists, as Lyell, Murchison,
+Sedgwick, &amp;c., have unanimously, often vehemently, maintained the
+immutability of species.  But I have reason to believe that one great
+authority, Sir Charles Lyell, from further reflexion entertains grave
+doubts on this subject.  I feel how rash it is to differ from these great
+authorities, to whom, with others, we owe all our knowledge.  Those who
+think the natural geological record in any degree perfect, and who do not
+attach much weight to the facts and arguments of other kinds given in this
+volume, will undoubtedly at once reject my theory.  For my part, following
+out Lyell's metaphor, I look at the natural geological record, as a history
+of the world imperfectly kept, and written in a changing dialect; of this
+history we possess the last volume alone, relating only to two or three
+countries.  Of this volume, only here and there a short chapter has been
+preserved; and of each page, only here and there a few lines.  Each word of
+the slowly-changing language, in which the history is supposed to be
+written, being more or less different in the interrupted succession of
+chapters, may represent the apparently abruptly changed forms of life,
+entombed in our consecutive, but widely separated formations.  On this
+view, the difficulties above discussed are greatly diminished, or even
+disappear.
+</para>
+
+</chapter>
+
+<chapter>
+<chapheader>
+
+<chapnum>Chapter X</chapnum>
+
+<title>On the Geological Succession of Organic Beings</title>
+
+<chapsummary>
+On the slow and successive appearance of new species -- On their different
+rates of change -- Species once lost do not reappear -- Groups of species
+follow the same general rules in their appearance and disappearance as do
+single species -- On Extinction -- On simultaneous changes in the forms of
+life throughout the world -- On the affinities of extinct species to each
+other and to living species -- On the state of development of ancient forms
+-- On the succession of the same types within the same areas -- Summary of
+preceding and present chapters.
+</chapsummary>
+</chapheader>
+
+<para>
+Let us now see whether the several facts and rules relating to the
+geological succession of organic beings, better accord with the common view
+of the immutability of species, or with that of their slow and gradual
+modification, through descent and natural selection.
+</para>
+
+<para>
+New species have appeared very slowly, one after another, both on the land
+and in the waters.  Lyell has shown that it is hardly possible to resist
+the evidence on this head in the case of the several tertiary stages; and
+every year tends to fill up the blanks between them, and to make the
+percentage system of lost and new forms more gradual.  In some of the most
+recent beds, though undoubtedly of high antiquity if measured by years,
+only one or two species are lost forms, and only one or two are new forms,
+having here appeared for the first time, either locally, or, as far as we
+know, on the face of the earth.  If we may trust the observations of
+Philippi in Sicily, the successive changes in the marine inhabitants of
+that island have been many and most gradual.  The secondary formations are
+more broken; but, as Bronn has remarked, neither the appearance nor
+disappearance of their many now extinct species has been simultaneous in
+each separate formation.
+</para>
+
+<para>
+Species of different genera and classes have not changed at the same rate,
+or in the same degree.  In the oldest tertiary beds a few living shells may
+still be found in the midst of a multitude of extinct forms.  Falconer has
+given a striking instance of a similar fact, in an existing crocodile
+associated with many strange and lost mammals and reptiles in the
+sub-Himalayan deposits.  The Silurian Lingula differs but little from the
+living species of this genus; whereas most of the other Silurian Molluscs
+and all the Crustaceans have changed greatly.  The productions of the land
+seem to change at a quicker rate than those of the sea, of which a striking
+instance has lately been observed in Switzerland.  There is some reason to
+believe that organisms, considered high in the scale of nature, change more
+quickly than those that are low:  though there are exceptions to this rule. 
+The amount of organic change, as Pictet has remarked, does not strictly
+correspond with the succession of our geological formations; so that
+between each two consecutive formations, the forms of life have seldom
+changed in exactly the same degree.  Yet if we compare any but the most
+closely related formations, all the species will be found to have undergone
+some change.  When a species has once disappeared from the face of the
+earth, we have reason to believe that the same identical form never
+reappears.  The strongest apparent exception to this latter rule, is that
+of the so-called 'colonies' of M. Barrande, which intrude for a period in
+the midst of an older formation, and then allow the pre-existing fauna to
+reappear; but Lyell's explanation, namely, that it is a case of temporary
+migration from a distinct geographical province, seems to me satisfactory.
+</para>
+
+<para>
+These several facts accord well with my theory.  I believe in no fixed law
+of development, causing all the inhabitants of a country to change
+abruptly, or simultaneously, or to an equal degree.  The process of
+modification must be extremely slow.  The variability of each species is
+quite independent of that of all others.  Whether such variability be taken
+advantage of by natural selection, and whether the variations be
+accumulated to a greater or lesser amount, thus causing a greater or lesser
+amount of modification in the varying species, depends on many complex
+contingencies,--on the variability being of a beneficial nature, on the
+power of intercrossing, on the rate of breeding, on the slowly changing
+physical conditions of the country, and more especially on the nature of
+the other inhabitants with which the varying species comes into
+competition.  Hence it is by no means surprising that one species should
+retain the same identical form much longer than others; or, if changing,
+that it should change less.  We see the same fact in geographical
+distribution; for instance, in the land-shells and coleopterous insects of
+Madeira having come to differ considerably from their nearest allies on the
+continent of Europe, whereas the marine shells and birds have remained
+unaltered.  We can perhaps understand the apparently quicker rate of change
+in terrestrial and in more highly organised productions compared with
+marine and lower productions, by the more complex relations of the higher
+beings to their organic and inorganic conditions of life, as explained in a
+former chapter.  When many of the inhabitants of a country have become
+modified and improved, we can understand, on the principle of competition,
+and on that of the many all-important relations of organism to organism,
+that any form which does not become in some degree modified and improved,
+will be liable to be exterminated.  Hence we can see why all the species in
+the same region do at last, if we look to wide enough intervals of time,
+become modified; for those which do not change will become extinct.
+</para>
+
+<para>
+In members of the same class the average amount of change, during long and
+equal periods of time, may, perhaps, be nearly the same; but as the
+accumulation of long-enduring fossiliferous formations depends on great
+masses of sediment having been deposited on areas whilst subsiding, our
+formations have been almost necessarily accumulated at wide and irregularly
+intermittent intervals; consequently the amount of organic change exhibited
+by the fossils embedded in consecutive formations is not equal.  Each
+formation, on this view, does not mark a new and complete act of creation,
+but only an occasional scene, taken almost at hazard, in a slowly changing
+drama.
+</para>
+
+<para>
+We can clearly understand why a species when once lost should never
+reappear, even if the very same conditions of life, organic and inorganic,
+should recur.  For though the offspring of one species might be adapted
+(and no doubt this has occurred in innumerable instances) to fill the exact
+place of another species in the economy of nature, and thus supplant it;
+yet the two forms--the old and the new--would not be identically the same;
+for both would almost certainly inherit different characters from their
+distinct progenitors.  For instance, it is just possible, if our
+fantail-pigeons were all destroyed, that fanciers, by striving during long
+ages for the same object, might make a new breed hardly distinguishable
+from our present fantail; but if the parent rock-pigeon were also
+destroyed, and in nature we have every reason to believe that the
+parent-form will generally be supplanted and exterminated by its improved
+offspring, it is quite incredible that a fantail, identical with the
+existing breed, could be raised from any other species of pigeon, or even
+from the other well-established races of the domestic pigeon, for the
+newly-formed fantail would be almost sure to inherit from its new
+progenitor some slight characteristic differences.
+</para>
+
+<para>
+Groups of species, that is, genera and families, follow the same general
+rules in their appearance and disappearance as do single species, changing
+more or less quickly, and in a greater or lesser degree.  A group does not
+reappear after it has once disappeared; or its existence, as long as it
+lasts, is continuous.  I am aware that there are some apparent exceptions
+to this rule, but the exceptions are surprisingly few, so few, that E.
+Forbes, Pictet, and Woodward (though all strongly opposed to such views as
+I maintain) admit its truth; and the rule strictly accords with my theory. 
+For as all the species of the same group have descended from some one
+species, it is clear that as long as any species of the group have appeared
+in the long succession of ages, so long must its members have continuously
+existed, in order to have generated either new and modified or the same old
+and unmodified forms.  Species of the genus Lingula, for instance, must
+have continuously existed by an unbroken succession of generations, from
+the lowest Silurian stratum to the present day.
+</para>
+
+<para>
+We have seen in the last chapter that the species of a group sometimes
+falsely appear to have come in abruptly; and I have attempted to give an
+explanation of this fact, which if true would have been fatal to my views. 
+But such cases are certainly exceptional; the general rule being a gradual
+increase in number, till the group reaches its maximum, and then, sooner or
+later, it gradually decreases.  If the number of the species of a genus, or
+the number of the genera of a family, be represented by a vertical line of
+varying thickness, crossing the successive geological formations in which
+the species are found, the line will sometimes falsely appear to begin at
+its lower end, not in a sharp point, but abruptly; it then gradually
+thickens upwards, sometimes keeping for a space of equal thickness, and
+ultimately thins out in the upper beds, marking the decrease and final
+extinction of the species.  This gradual increase in number of the species
+of a group is strictly conformable with my theory; as the species of the
+same genus, and the genera of the same family, can increase only slowly and
+progressively; for the process of modification and the production of a
+number of allied forms must be slow and gradual,--one species giving rise
+first to two or three varieties, these being slowly converted into species,
+which in their turn produce by equally slow steps other species, and so on,
+like the branching of a great tree from a single stem, till the group
+becomes large.
+</para>
+
+<para>
+On Extinction. -- We have as yet spoken only incidentally of the
+disappearance of species and of groups of species.  On the theory of
+natural selection the extinction of old forms and the production of new and
+improved forms are intimately connected together.  The old notion of all
+the inhabitants of the earth having been swept away at successive periods
+by catastrophes, is very generally given up, even by those geologists, as
+Elie de Beaumont, Murchison, Barrande, &amp;c., whose general views would
+naturally lead them to this conclusion.  On the contrary, we have every
+reason to believe, from the study of the tertiary formations, that species
+and groups of species gradually disappear, one after another, first from
+one spot, then from another, and finally from the world.  Both single
+species and whole groups of species last for very unequal periods; some
+groups, as we have seen, having endured from the earliest known dawn of
+life to the present day; some having disappeared before the close of the
+palaeozoic period.  No fixed law seems to determine the length of time
+during which any single species or any single genus endures.  There is
+reason to believe that the complete extinction of the species of a group is
+generally a slower process than their production:  if the appearance and
+disappearance of a group of species be represented, as before, by a
+vertical line of varying thickness, the line is found to taper more
+gradually at its upper end, which marks the progress of extermination, than
+at its lower end, which marks the first appearance and increase in numbers
+of the species.  In some cases, however, the extermination of whole groups
+of beings, as of ammonites towards the close of the secondary period, has
+been wonderfully sudden.
+</para>
+
+<para>
+The whole subject of the extinction of species has been involved in the
+most gratuitous mystery.  Some authors have even supposed that as the
+individual has a definite length of life, so have species a definite
+duration.  No one I think can have marvelled more at the extinction of
+species, than I have done.  When I found in La Plata the tooth of a horse
+embedded with the remains of Mastodon, Megatherium, Toxodon, and other
+extinct monsters, which all co-existed with still living shells at a very
+late geological period, I was filled with astonishment; for seeing that the
+horse, since its introduction by the Spaniards into South America, has run
+wild over the whole country and has increased in numbers at an unparalleled
+rate, I asked myself what could so recently have exterminated the former
+horse under conditions of life apparently so favourable.  But how utterly
+groundless was my astonishment!  Professor Owen soon perceived that the
+tooth, though so like that of the existing horse, belonged to an extinct
+species.  Had this horse been still living, but in some degree rare, no
+naturalist would have felt the least surprise at its rarity; for rarity is
+the attribute of a vast number of species of all classes, in all countries. 
+If we ask ourselves why this or that species is rare, we answer that
+something is unfavourable in its conditions of life; but what that
+something is, we can hardly ever tell.  On the supposition of the fossil
+horse still existing as a rare species, we might have felt certain from the
+analogy of all other mammals, even of the slow-breeding elephant, and from
+the history of the naturalisation of the domestic horse in South America,
+that under more favourable conditions it would in a very few years have
+stocked the whole continent.  But we could not have told what the
+unfavourable conditions were which checked its increase, whether some one
+or several contingencies, and at what period of the horse's life, and in
+what degree, they severally acted.  If the conditions had gone on, however
+slowly, becoming less and less favourable, we assuredly should not have
+perceived the fact, yet the fossil horse would certainly have become rarer
+and rarer, and finally extinct;--its place being seized on by some more
+successful competitor.
+</para>
+
+<para>
+It is most difficult always to remember that the increase of every living
+being is constantly being checked by unperceived injurious agencies; and
+that these same unperceived agencies are amply sufficient to cause rarity,
+and finally extinction.  We see in many cases in the more recent tertiary
+formations, that rarity precedes extinction; and we know that this has been
+the progress of events with those animals which have been exterminated,
+either locally or wholly, through man's agency.  I may repeat what I
+published in 1845, namely, that to admit that species generally become rare
+before they become extinct--to feel no surprise at the rarity of a species,
+and yet to marvel greatly when it ceases to exist, is much the same as to
+admit that sickness in the individual is the forerunner of death--to feel
+no surprise at sickness, but when the sick man dies, to wonder and to
+suspect that he died by some unknown deed of violence.
+</para>
+
+<para>
+The theory of natural selection is grounded on the belief that each new
+variety, and ultimately each new species, is produced and maintained by
+having some advantage over those with which it comes into competition; and
+the consequent extinction of less-favoured forms almost inevitably follows. 
+It is the same with our domestic productions:  when a new and slightly
+improved variety has been raised, it at first supplants the less improved
+varieties in the same neighbourhood; when much improved it is transported
+far and near, like our short-horn cattle, and takes the place of other
+breeds in other countries.  Thus the appearance of new forms and the
+disappearance of old forms, both natural and artificial, are bound
+together.  In certain flourishing groups, the number of new specific forms
+which have been produced within a given time is probably greater than that
+of the old forms which have been exterminated; but we know that the number
+of species has not gone on indefinitely increasing, at least during the
+later geological periods, so that looking to later times we may believe
+that the production of new forms has caused the extinction of about the
+same number of old forms.
+</para>
+
+<para>
+The competition will generally be most severe, as formerly explained and
+illustrated by examples, between the forms which are most like each other
+in all respects.  Hence the improved and modified descendants of a species
+will generally cause the extermination of the parent-species; and if many
+new forms have been developed from any one species, the nearest allies of
+that species, i.e. the species of the same genus, will be the most liable
+to extermination.  Thus, as I believe, a number of new species descended
+from one species, that is a new genus, comes to supplant an old genus,
+belonging to the same family.  But it must often have happened that a new
+species belonging to some one group will have seized on the place occupied
+by a species belonging to a distinct group, and thus caused its
+extermination; and if many allied forms be developed from the successful
+intruder, many will have to yield their places; and it will generally be
+allied forms, which will suffer from some inherited inferiority in common. 
+But whether it be species belonging to the same or to a distinct class,
+which yield their places to other species which have been modified and
+improved, a few of the sufferers may often long be preserved, from being
+fitted to some peculiar line of life, or from inhabiting some distant and
+isolated station, where they have escaped severe competition.  For
+instance, a single species of Trigonia, a great genus of shells in the
+secondary formations, survives in the Australian seas; and a few members of
+the great and almost extinct group of Ganoid fishes still inhabit our fresh
+waters.  Therefore the utter extinction of a group is generally, as we have
+seen, a slower process than its production.
+</para>
+
+<para>
+With respect to the apparently sudden extermination of whole families or
+orders, as of Trilobites at the close of the palaeozoic period and of
+Ammonites at the close of the secondary period, we must remember what has
+been already said on the probable wide intervals of time between our
+consecutive formations; and in these intervals there may have been much
+slow extermination.  Moreover, when by sudden immigration or by unusually
+rapid development, many species of a new group have taken possession of a
+new area, they will have exterminated in a correspondingly rapid manner
+many of the old inhabitants; and the forms which thus yield their places
+will commonly be allied, for they will partake of some inferiority in
+common.
+</para>
+
+<para>
+Thus, as it seems to me, the manner in which single species and whole
+groups of species become extinct, accords well with the theory of natural
+selection.  We need not marvel at extinction; if we must marvel, let it be
+at our presumption in imagining for a moment that we understand the many
+complex contingencies, on which the existence of each species depends.  If
+we forget for an instant, that each species tends to increase inordinately,
+and that some check is always in action, yet seldom perceived by us, the
+whole economy of nature will be utterly obscured.  Whenever we can
+precisely say why this species is more abundant in individuals than that;
+why this species and not another can be naturalised in a given country;
+then, and not till then, we may justly feel surprise why we cannot account
+for the extinction of this particular species or group of species.
+</para>
+
+<para>
+On the Forms of Life changing almost simultaneously throughout the World. -
+- Scarcely any palaeontological discovery is more striking than the fact,
+that the forms of life change almost simultaneously throughout the world. 
+Thus our European Chalk formation can be recognised in many distant parts
+of the world, under the most different climates, where not a fragment of
+the mineral chalk itself can be found; namely, in North America, in
+equatorial South America, in Tierra del Fuego, at the Cape of Good Hope,
+and in the peninsula of India.  For at these distant points, the organic
+remains in certain beds present an unmistakeable degree of resemblance to
+those of the Chalk.  It is not that the same species are met with; for in
+some cases not one species is identically the same, but they belong to the
+same families, genera, and sections of genera, and sometimes are similarly
+characterised in such trifling points as mere superficial sculpture. 
+Moreover other forms, which are not found in the Chalk of Europe, but which
+occur in the formations either above or below, are similarly absent at
+these distant points of the world.  In the several successive palaeozoic
+formations of Russia, Western Europe and North America, a similar
+parallelism in the forms of life has been observed by several authors:  so
+it is, according to Lyell, with the several European and North American
+tertiary deposits.  Even if the few fossil species which are common to the
+Old and New Worlds be kept wholly out of view, the general parallelism in
+the successive forms of life, in the stages of the widely separated
+palaeozoic and tertiary periods, would still be manifest, and the several
+formations could be easily correlated.
+</para>
+
+<para>
+These observations, however, relate to the marine inhabitants of distant
+parts of the world:  we have not sufficient data to judge whether the
+productions of the land and of fresh water change at distant points in the
+same parallel manner.  We may doubt whether they have thus changed:  if the
+Megatherium, Mylodon, Macrauchenia, and Toxodon had been brought to Europe
+from La Plata, without any information in regard to their geological
+position, no one would have suspected that they had coexisted with still
+living sea-shells; but as these anomalous monsters coexisted with the
+Mastodon and Horse, it might at least have been inferred that they had
+lived during one of the latter tertiary stages.
+</para>
+
+<para>
+When the marine forms of life are spoken of as having changed
+simultaneously throughout the world, it must not be supposed that this
+expression relates to the same thousandth or hundred-thousandth year, or
+even that it has a very strict geological sense; for if all the marine
+animals which live at the present day in Europe, and all those that lived
+in Europe during the pleistocene period (an enormously remote period as
+measured by years, including the whole glacial epoch), were to be compared
+with those now living in South America or in Australia, the most skilful
+naturalist would hardly be able to say whether the existing or the
+pleistocene inhabitants of Europe resembled most closely those of the
+southern hemisphere.  So, again, several highly competent observers believe
+that the existing productions of the United States are more closely related
+to those which lived in Europe during certain later tertiary stages, than
+to those which now live here; and if this be so, it is evident that
+fossiliferous beds deposited at the present day on the shores of North
+America would hereafter be liable to be classed with somewhat older
+European beds.  Nevertheless, looking to a remotely future epoch, there
+can, I think, be little doubt that all the more modern marine formations,
+namely, the upper pliocene, the pleistocene and strictly modern beds, of
+Europe, North and South America, and Australia, from containing fossil
+remains in some degree allied, and from not including those forms which are
+only found in the older underlying deposits, would be correctly ranked as
+simultaneous in a geological sense.
+</para>
+
+<para>
+The fact of the forms of life changing simultaneously, in the above large
+sense, at distant parts of the world, has greatly struck those admirable
+observers, MM. de Verneuil and d'Archiac.  After referring to the
+parallelism of the palaeozoic forms of life in various parts of Europe,
+they add, 'If struck by this strange sequence, we turn our attention to
+North America, and there discover a series of analogous phenomena, it will
+appear certain that all these modifications of species, their extinction,
+and the introduction of new ones, cannot be owing to mere changes in marine
+currents or other causes more or less local and temporary, but depend on
+general laws which govern the whole animal kingdom.'  M. Barrande has made
+forcible remarks to precisely the same effect.  It is, indeed, quite futile
+to look to changes of currents, climate, or other physical conditions, as
+the cause of these great mutations in the forms of life throughout the
+world, under the most different climates.  We must, as Barrande has
+remarked, look to some special law.  We shall see this more clearly when we
+treat of the present distribution of organic beings, and find how slight is
+the relation between the physical conditions of various countries, and the
+nature of their inhabitants.
+</para>
+
+<para>
+This great fact of the parallel succession of the forms of life throughout
+the world, is explicable on the theory of natural selection.  New species
+are formed by new varieties arising, which have some advantage over older
+forms; and those forms, which are already dominant, or have some advantage
+over the other forms in their own country, would naturally oftenest give
+rise to new varieties or incipient species; for these latter must be
+victorious in a still higher degree in order to be preserved and to
+survive.  We have distinct evidence on this head, in the plants which are
+dominant, that is, which are commonest in their own homes, and are most
+widely diffused, having produced the greatest number of new varieties.  It
+is also natural that the dominant, varying, and far-spreading species,
+which already have invaded to a certain extent the territories of other
+species, should be those which would have the best chance of spreading
+still further, and of giving rise in new countries to new varieties and
+species.  The process of diffusion may often be very slow, being dependent
+on climatal and geographical changes, or on strange accidents, but in the
+long run the dominant forms will generally succeed in spreading.  The
+diffusion would, it is probable, be slower with the terrestrial inhabitants
+of distinct continents than with the marine inhabitants of the continuous
+sea.  We might therefore expect to find, as we apparently do find, a less
+strict degree of parallel succession in the productions of the land than of
+the sea.
+</para>
+
+<para>
+Dominant species spreading from any region might encounter still more
+dominant species, and then their triumphant course, or even their
+existence, would cease.  We know not at all precisely what are all the
+conditions most favourable for the multiplication of new and dominant
+species; but we can, I think, clearly see that a number of individuals,
+from giving a better chance of the appearance of favourable variations, and
+that severe competition with many already existing forms, would be highly
+favourable, as would be the power of spreading into new territories.  A
+certain amount of isolation, recurring at long intervals of time, would
+probably be also favourable, as before explained.  One quarter of the world
+may have been most favourable for the production of new and dominant
+species on the land, and another for those in the waters of the sea.  If
+two great regions had been for a long period favourably circumstanced in an
+equal degree, whenever their inhabitants met, the battle would be prolonged
+and severe; and some from one birthplace and some from the other might be
+victorious.  But in the course of time, the forms dominant in the highest
+degree, wherever produced, would tend everywhere to prevail.  As they
+prevailed, they would cause the extinction of other and inferior forms; and
+as these inferior forms would be allied in groups by inheritance, whole
+groups would tend slowly to disappear; though here and there a single
+member might long be enabled to survive.
+</para>
+
+<para>
+Thus, as it seems to me, the parallel, and, taken in a large sense,
+simultaneous, succession of the same forms of life throughout the world,
+accords well with the principle of new species having been formed by
+dominant species spreading widely and varying; the new species thus
+produced being themselves dominant owing to inheritance, and to having
+already had some advantage over their parents or over other species; these
+again spreading, varying, and producing new species.  The forms which are
+beaten and which yield their places to the new and victorious forms, will
+generally be allied in groups, from inheriting some inferiority in common;
+and therefore as new and improved groups spread throughout the world, old
+groups will disappear from the world; and the succession of forms in both
+ways will everywhere tend to correspond.
+</para>
+
+<para>
+There is one other remark connected with this subject worth making.  I have
+given my reasons for believing that all our greater fossiliferous
+formations were deposited during periods of subsidence; and that blank
+intervals of vast duration occurred during the periods when the bed of the
+sea was either stationary or rising, and likewise when sediment was not
+thrown down quickly enough to embed and preserve organic remains.  During
+these long and blank intervals I suppose that the inhabitants of each
+region underwent a considerable amount of modification and extinction, and
+that there was much migration from other parts of the world.  As we have
+reason to believe that large areas are affected by the same movement, it is
+probable that strictly contemporaneous formations have often been
+accumulated over very wide spaces in the same quarter of the world; but we
+are far from having any right to conclude that this has invariably been the
+case, and that large areas have invariably been affected by the same
+movements.  When two formations have been deposited in two regions during
+nearly, but not exactly the same period, we should find in both, from the
+causes explained in the foregoing paragraphs, the same general succession
+in the forms of life; but the species would not exactly correspond; for
+there will have been a little more time in the one region than in the other
+for modification, extinction, and immigration.
+</para>
+
+<para>
+I suspect that cases of this nature have occurred in Europe.  Mr.
+Prestwich, in his admirable Memoirs on the eocene deposits of England and
+France, is able to draw a close general parallelism between the successive
+stages in the two countries; but when he compares certain stages in England
+with those in France, although he finds in both a curious accordance in the
+numbers of the species belonging to the same genera, yet the species
+themselves differ in a manner very difficult to account for, considering
+the proximity of the two areas,--unless, indeed, it be assumed that an
+isthmus separated two seas inhabited by distinct, but contemporaneous,
+faunas.  Lyell has made similar observations on some of the later tertiary
+formations.  Barrande, also, shows that there is a striking general
+parallelism in the successive Silurian deposits of Bohemia and Scandinavia;
+nevertheless he finds a surprising amount of difference in the species.  If
+the several formations in these regions have not been deposited during the
+same exact periods,--a formation in one region often corresponding with a
+blank interval in the other,--and if in both regions the species have gone
+on slowly changing during the accumulation of the several formations and
+during the long intervals of time between them; in this case, the several
+formations in the two regions could be arranged in the same order, in
+accordance with the general succession of the form of life, and the order
+would falsely appear to be strictly parallel; nevertheless the species
+would not all be the same in the apparently corresponding stages in the two
+regions.
+</para>
+
+<para>
+On the Affinities of extinct Species to each other, and to living forms. --
+Let us now look to the mutual affinities of extinct and living species. 
+They all fall into one grand natural system; and this fact is at once
+explained on the principle of descent.  The more ancient any form is, the
+more, as a general rule, it differs from living forms.  But, as Buckland
+long ago remarked, all fossils can be classed either in still existing
+groups, or between them.  That the extinct forms of life help to fill up
+the wide intervals between existing genera, families, and orders, cannot be
+disputed.  For if we confine our attention either to the living or to the
+extinct alone, the series is far less perfect than if we combine both into
+one general system.  With respect to the Vertebrata, whole pages could be
+filled with striking illustrations from our great palaeontologist, Owen,
+showing how extinct animals fall in between existing groups.  Cuvier ranked
+the Ruminants and Pachyderms, as the two most distinct orders of mammals;
+but Owen has discovered so many fossil links, that he has had to alter the
+whole classification of these two orders; and has placed certain pachyderms
+in the same sub-order with ruminants:  for example, he dissolves by fine
+gradations the apparently wide difference between the pig and the camel. 
+In regard to the Invertebrata, Barrande, and a higher authority could not
+be named, asserts that he is every day taught that palaeozoic animals,
+though belonging to the same orders, families, or genera with those living
+at the present day, were not at this early epoch limited in such distinct
+groups as they now are.
+</para>
+
+<para>
+Some writers have objected to any extinct species or group of species being
+considered as intermediate between living species or groups.  If by this
+term it is meant that an extinct form is directly intermediate in all its
+characters between two living forms, the objection is probably valid.  But
+I apprehend that in a perfectly natural classification many fossil species
+would have to stand between living species, and some extinct genera between
+living genera, even between genera belonging to distinct families.  The
+most common case, especially with respect to very distinct groups, such as
+fish and reptiles, seems to be, that supposing them to be distinguished at
+the present day from each other by a dozen characters, the ancient members
+of the same two groups would be distinguished by a somewhat lesser number
+of characters, so that the two groups, though formerly quite distinct, at
+that period made some small approach to each other.
+</para>
+
+<para>
+It is a common belief that the more ancient a form is, by so much the more
+it tends to connect by some of its characters groups now widely separated
+from each other.  This remark no doubt must be restricted to those groups
+which have undergone much change in the course of geological ages; and it
+would be difficult to prove the truth of the proposition, for every now and
+then even a living animal, as the Lepidosiren, is discovered having
+affinities directed towards very distinct groups.  Yet if we compare the
+older Reptiles and Batrachians, the older Fish, the older Cephalopods, and
+the eocene Mammals, with the more recent members of the same classes, we
+must admit that there is some truth in the remark.
+</para>
+
+<para>
+Let us see how far these several facts and inferences accord with the
+theory of descent with modification.  As the subject is somewhat complex, I
+must request the reader to turn to the diagram in the fourth chapter.  We
+may suppose that the numbered letters represent genera, and the dotted
+lines diverging from them the species in each genus.  The diagram is much
+too simple, too few genera and too few species being given, but this is
+unimportant for us.  The horizontal lines may represent successive
+geological formations, and all the forms beneath the uppermost line may be
+considered as extinct.  The three existing genera, a14, q14, p14, will form
+a small family; b14 and f14 a closely allied family or sub-family; and o14,
+e14, m14, a third family.  These three families, together with the many
+extinct genera on the several lines of descent diverging from the
+parent-form A, will form an order; for all will have inherited something in
+common from their ancient and common progenitor.  On the principle of the
+continued tendency to divergence of character, which was formerly
+illustrated by this diagram, the more recent any form is, the more it will
+generally differ from its ancient progenitor.  Hence we can understand the
+rule that the most ancient fossils differ most from existing forms.  We
+must not, however, assume that divergence of character is a necessary
+contingency; it depends solely on the descendants from a species being thus
+enabled to seize on many and different places in the economy of nature. 
+Therefore it is quite possible, as we have seen in the case of some
+Silurian forms, that a species might go on being slightly modified in
+relation to its slightly altered conditions of life, and yet retain
+throughout a vast period the same general characteristics.  This is
+represented in the diagram by the letter F14.
+</para>
+
+<para>
+All the many forms, extinct and recent, descended from A, make, as before
+remarked, one order; and this order, from the continued effects of
+extinction and divergence of character, has become divided into several
+sub-families and families, some of which are supposed to have perished at
+different periods, and some to have endured to the present day.
+</para>
+
+<para>
+By looking at the diagram we can see that if many of the extinct forms,
+supposed to be embedded in the successive formations, were discovered at
+several points low down in the series, the three existing families on the
+uppermost line would be rendered less distinct from each other.  If, for
+instance, the genera a1, a5, a10, f8, m3, m6, m9 were disinterred, these
+three families would be so closely linked together that they probably would
+have to be united into one great family, in nearly the same manner as has
+occurred with ruminants and pachyderms.  Yet he who objected to call the
+extinct genera, which thus linked the living genera of three families
+together, intermediate in character, would be justified, as they are
+intermediate, not directly, but only by a long and circuitous course
+through many widely different forms.  If many extinct forms were to be
+discovered above one of the middle horizontal lines or geological
+formations--for instance, above No. VI.--but none from beneath this line,
+then only the two families on the left hand (namely, a14, &amp;c., and b14,
+&amp;c.) would have to be united into one family; and the two other families
+(namely, a14 to f14 now including five genera, and o14 to m14) would yet
+remain distinct.  These two families, however, would be less distinct from
+each other than they were before the discovery of the fossils.  If, for
+instance, we suppose the existing genera of the two families to differ from
+each other by a dozen characters, in this case the genera, at the early
+period marked VI., would differ by a lesser number of characters; for at
+this early stage of descent they have not diverged in character from the
+common progenitor of the order, nearly so much as they subsequently
+diverged.  Thus it comes that ancient and extinct genera are often in some
+slight degree intermediate in character between their modified descendants,
+or between their collateral relations.
+</para>
+
+<para>
+In nature the case will be far more complicated than is represented in the
+diagram; for the groups will have been more numerous, they will have
+endured for extremely unequal lengths of time, and will have been modified
+in various degrees.  As we possess only the last volume of the geological
+record, and that in a very broken condition, we have no right to expect,
+except in very rare cases, to fill up wide intervals in the natural system,
+and thus unite distinct families or orders.  All that we have a right to
+expect, is that those groups, which have within known geological periods
+undergone much modification, should in the older formations make some
+slight approach to each other; so that the older members should differ less
+from each other in some of their characters than do the existing members of
+the same groups; and this by the concurrent evidence of our best
+palaeontologists seems frequently to be the case.
+</para>
+
+<para>
+Thus, on the theory of descent with modification, the main facts with
+respect to the mutual affinities of the extinct forms of life to each other
+and to living forms, seem to me explained in a satisfactory manner.  And
+they are wholly inexplicable on any other view.
+</para>
+
+<para>
+On this same theory, it is evident that the fauna of any great period in
+the earth's history will be intermediate in general character between that
+which preceded and that which succeeded it.  Thus, the species which lived
+at the sixth great stage of descent in the diagram are the modified
+offspring of those which lived at the fifth stage, and are the parents of
+those which became still more modified at the seventh stage; hence they
+could hardly fail to be nearly intermediate in character between the forms
+of life above and below.  We must, however, allow for the entire extinction
+of some preceding forms, and for the coming in of quite new forms by
+immigration, and for a large amount of modification, during the long and
+blank intervals between the successive formations.  Subject to these
+allowances, the fauna of each geological period undoubtedly is intermediate
+in character, between the preceding and succeeding faunas.  I need give
+only one instance, namely, the manner in which the fossils of the Devonian
+system, when this system was first discovered, were at once recognised by
+palaeontologists as intermediate in character between those of the
+overlying carboniferous, and underlying Silurian system.  But each fauna is
+not necessarily exactly intermediate, as unequal intervals of time have
+elapsed between consecutive formations.
+</para>
+
+<para>
+It is no real objection to the truth of the statement, that the fauna of
+each period as a whole is nearly intermediate in character between the
+preceding and succeeding faunas, that certain genera offer exceptions to
+the rule.  For instance, mastodons and elephants, when arranged by Dr.
+Falconer in two series, first according to their mutual affinities and then
+according to their periods of existence, do not accord in arrangement.  The
+species extreme in character are not the oldest, or the most recent; nor
+are those which are intermediate in character, intermediate in age.  But
+supposing for an instant, in this and other such cases, that the record of
+the first appearance and disappearance of the species was perfect, we have
+no reason to believe that forms successively produced necessarily endure
+for corresponding lengths of time:  a very ancient form might occasionally
+last much longer than a form elsewhere subsequently produced, especially in
+the case of terrestrial productions inhabiting separated districts.  To
+compare small things with great:  if the principal living and extinct races
+of the domestic pigeon were arranged as well as they could be in serial
+affinity, this arrangement would not closely accord with the order in time
+of their production, and still less with the order of their disappearance;
+for the parent rock-pigeon now lives; and many varieties between the
+rock-pigeon and the carrier have become extinct; and carriers which are
+extreme in the important character of length of beak originated earlier
+than short-beaked tumblers, which are at the opposite end of the series in
+this same respect.
+</para>
+
+<para>
+Closely connected with the statement, that the organic remains from an
+intermediate formation are in some degree intermediate in character, is the
+fact, insisted on by all palaeontologists, that fossils from two
+consecutive formations are far more closely related to each other, than are
+the fossils from two remote formations.  Pictet gives as a well-known
+instance, the general resemblance of the organic remains from the several
+stages of the chalk formation, though the species are distinct in each
+stage.  This fact alone, from its generality, seems to have shaken
+Professor Pictet in his firm belief in the immutability of species.  He who
+is acquainted with the distribution of existing species over the globe,
+will not attempt to account for the close resemblance of the distinct
+species in closely consecutive formations, by the physical conditions of
+the ancient areas having remained nearly the same.  Let it be remembered
+that the forms of life, at least those inhabiting the sea, have changed
+almost simultaneously throughout the world, and therefore under the most
+different climates and conditions.  Consider the prodigious vicissitudes of
+climate during the pleistocene period, which includes the whole glacial
+period, and note how little the specific forms of the inhabitants of the
+sea have been affected.
+</para>
+
+<para>
+On the theory of descent, the full meaning of the fact of fossil remains
+from closely consecutive formations, though ranked as distinct species,
+being closely related, is obvious.  As the accumulation of each formation
+has often been interrupted, and as long blank intervals have intervened
+between successive formations, we ought not to expect to find, as I
+attempted to show in the last chapter, in any one or two formations all the
+intermediate varieties between the species which appeared at the
+commencement and close of these periods; but we ought to find after
+intervals, very long as measured by years, but only moderately long as
+measured geologically, closely allied forms, or, as they have been called
+by some authors, representative species; and these we assuredly do find. 
+We find, in short, such evidence of the slow and scarcely sensible mutation
+of specific forms, as we have a just right to expect to find.
+</para>
+
+<para>
+On the state of Development of Ancient Forms. -- There has been much
+discussion whether recent forms are more highly developed than ancient.  I
+will not here enter on this subject, for naturalists have not as yet
+defined to each other's satisfaction what is meant by high and low forms. 
+But in one particular sense the more recent forms must, on my theory, be
+higher than the more ancient; for each new species is formed by having had
+some advantage in the struggle for life over other and preceding forms.  If
+under a nearly similar climate, the eocene inhabitants of one quarter of
+the world were put into competition with the existing inhabitants of the
+same or some other quarter, the eocene fauna or flora would certainly be
+beaten and exterminated; as would a secondary fauna by an eocene, and a
+palaeozoic fauna by a secondary fauna.  I do not doubt that this process of
+improvement has affected in a marked and sensible manner the organisation
+of the more recent and victorious forms of life, in comparison with the
+ancient and beaten forms; but I can see no way of testing this sort of
+progress.  Crustaceans, for instance, not the highest in their own class,
+may have beaten the highest molluscs.  From the extraordinary manner in
+which European productions have recently spread over New Zealand, and have
+seized on places which must have been previously occupied, we may believe,
+if all the animals and plants of Great Britain were set free in New
+Zealand, that in the course of time a multitude of British forms would
+become thoroughly naturalized there, and would exterminate many of the
+natives.  On the other hand, from what we see now occurring in New Zealand,
+and from hardly a single inhabitant of the southern hemisphere having
+become wild in any part of Europe, we may doubt, if all the productions of
+New Zealand were set free in Great Britain, whether any considerable number
+would be enabled to seize on places now occupied by our native plants and
+animals.  Under this point of view, the productions of Great Britain may be
+said to be higher than those of New Zealand.  Yet the most skilful
+naturalist from an examination of the species of the two countries could
+not have foreseen this result.
+</para>
+
+<para>
+Agassiz insists that ancient animals resemble to a certain extent the
+embryos of recent animals of the same classes; or that the geological
+succession of extinct forms is in some degree parallel to the embryological
+development of recent forms.  I must follow Pictet and Huxley in thinking
+that the truth of this doctrine is very far from proved.  Yet I fully
+expect to see it hereafter confirmed, at least in regard to subordinate
+groups, which have branched off from each other within comparatively recent
+times.  For this doctrine of Agassiz accords well with the theory of
+natural selection.  In a future chapter I shall attempt to show that the
+adult differs from its embryo, owing to variations supervening at a not
+early age, and being inherited at a corresponding age.  This process,
+whilst it leaves the embryo almost unaltered, continually adds, in the
+course of successive generations, more and more difference to the adult.
+</para>
+
+<para>
+Thus the embryo comes to be left as a sort of picture, preserved by nature,
+of the ancient and less modified condition of each animal.  This view may
+be true, and yet it may never be capable of full proof.  Seeing, for
+instance, that the oldest known mammals, reptiles, and fish strictly belong
+to their own proper classes, though some of these old forms are in a slight
+degree less distinct from each other than are the typical members of the
+same groups at the present day, it would be vain to look for animals having
+the common embryological character of the Vertebrata, until beds far
+beneath the lowest Silurian strata are discovered--a discovery of which the
+chance is very small.
+</para>
+
+<para>
+On the Succession of the same Types within the same areas, during the later
+tertiary periods. -- Mr. Clift many years ago showed that the fossil
+mammals from the Australian caves were closely allied to the living
+marsupials of that continent.  In South America, a similar relationship is
+manifest, even to an uneducated eye, in the gigantic pieces of armour like
+those of the armadillo, found in several parts of La Plata; and Professor
+Owen has shown in the most striking manner that most of the fossil mammals,
+buried there in such numbers, are related to South American types.  This
+relationship is even more clearly seen in the wonderful collection of
+fossil bones made by MM. Lund and Clausen in the caves of Brazil.  I was so
+much impressed with these facts that I strongly insisted, in 1839 and 1845,
+on this 'law of the succession of types,'--on 'this wonderful relationship
+in the same continent between the dead and the living.'  Professor Owen has
+subsequently extended the same generalisation to the mammals of the Old
+World.  We see the same law in this author's restorations of the extinct
+and gigantic birds of New Zealand.  We see it also in the birds of the
+caves of Brazil.  Mr. Woodward has shown that the same law holds good with
+sea-shells, but from the wide distribution of most genera of molluscs, it
+is not well displayed by them.  Other cases could be added, as the relation
+between the extinct and living land-shells of Madeira; and between the
+extinct and living brackish-water shells of the Aralo-Caspian Sea.
+</para>
+
+<para>
+Now what does this remarkable law of the succession of the same types
+within the same areas mean?  He would be a bold man, who after comparing
+the present climate of Australia and of parts of South America under the
+same latitude, would attempt to account, on the one hand, by dissimilar
+physical conditions for the dissimilarity of the inhabitants of these two
+continents, and, on the other hand, by similarity of conditions, for the
+uniformity of the same types in each during the later tertiary periods. 
+Nor can it be pretended that it is an immutable law that marsupials should
+have been chiefly or solely produced in Australia; or that Edentata and
+other American types should have been solely produced in South America. 
+For we know that Europe in ancient times was peopled by numerous
+marsupials; and I have shown in the publications above alluded to, that in
+America the law of distribution of terrestrial mammals was formerly
+different from what it now is.  North America formerly partook strongly of
+the present character of the southern half of the continent; and the
+southern half was formerly more closely allied, than it is at present, to
+the northern half.  In a similar manner we know from Falconer and Cautley's
+discoveries, that northern India was formerly more closely related in its
+mammals to Africa than it is at the present time.  Analogous facts could be
+given in relation to the distribution of marine animals.
+</para>
+
+<para>
+On the theory of descent with modification, the great law of the long
+enduring, but not immutable, succession of the same types within the same
+areas, is at once explained; for the inhabitants of each quarter of the
+world will obviously tend to leave in that quarter, during the next
+succeeding period of time, closely allied though in some degree modified
+descendants.  If the inhabitants of one continent formerly differed greatly
+from those of another continent, so will their modified descendants still
+differ in nearly the same manner and degree.  But after very long intervals
+of time and after great geographical changes, permitting much
+inter-migration, the feebler will yield to the more dominant forms, and
+there will be nothing immutable in the laws of past and present
+distribution.
+</para>
+
+<para>
+It may be asked in ridicule, whether I suppose that the megatherium and
+other allied huge monsters have left behind them in South America the
+sloth, armadillo, and anteater, as their degenerate descendants.  This
+cannot for an instant be admitted.  These huge animals have become wholly
+extinct, and have left no progeny.  But in the caves of Brazil, there are
+many extinct species which are closely allied in size and in other
+characters to the species still living in South America; and some of these
+fossils may be the actual progenitors of living species.  It must not be
+forgotten that, on my theory, all the species of the same genus have
+descended from some one species; so that if six genera, each having eight
+species, be found in one geological formation, and in the next succeeding
+formation there be six other allied or representative genera with the same
+number of species, then we may conclude that only one species of each of
+the six older genera has left modified descendants, constituting the six
+new genera.  The other seven species of the old genera have all died out
+and have left no progeny.  Or, which would probably be a far commoner case,
+two or three species of two or three alone of the six older genera will
+have been the parents of the six new genera; the other old species and the
+other whole genera having become utterly extinct.  In failing orders, with
+the genera and species decreasing in numbers, as apparently is the case of
+the Edentata of South America, still fewer genera and species will have
+left modified blood-descendants.
+</para>
+
+<para>
+Summary of the preceding and present Chapters -- I have attempted to show
+that the geological record is extremely imperfect; that only a small
+portion of the globe has been geologically explored with care; that only
+certain classes of organic beings have been largely preserved in a fossil
+state; that the number both of specimens and of species, preserved in our
+museums, is absolutely as nothing compared with the incalculable number of
+generations which must have passed away even during a single formation;
+that, owing to subsidence being necessary for the accumulation of
+fossiliferous deposits thick enough to resist future degradation, enormous
+intervals of time have elapsed between the successive formations; that
+there has probably been more extinction during the periods of subsidence,
+and more variation during the periods of elevation, and during the latter
+the record will have been least perfectly kept; that each single formation
+has not been continuously deposited; that the duration of each formation
+is, perhaps, short compared with the average duration of specific forms;
+that migration has played an important part in the first appearance of new
+forms in any one area and formation; that widely ranging species are those
+which have varied most, and have oftenest given rise to new species; and
+that varieties have at first often been local.  All these causes taken
+conjointly, must have tended to make the geological record extremely
+imperfect, and will to a large extent explain why we do not find
+interminable varieties, connecting together all the extinct and existing
+forms of life by the finest graduated steps.
+</para>
+
+<para>
+He who rejects these views on the nature of the geological record, will
+rightly reject my whole theory.  For he may ask in vain where are the
+numberless transitional links which must formerly have connected the
+closely allied or representative species, found in the several stages of
+the same great formation.  He may disbelieve in the enormous intervals of
+time which have elapsed between our consecutive formations; he may overlook
+how important a part migration must have played, when the formations of any
+one great region alone, as that of Europe, are considered; he may urge the
+apparent, but often falsely apparent, sudden coming in of whole groups of
+species.  He may ask where are the remains of those infinitely numerous
+organisms which must have existed long before the first bed of the Silurian
+system was deposited:  I can answer this latter question only
+hypothetically, by saying that as far as we can see, where our oceans now
+extend they have for an enormous period extended, and where our oscillating
+continents now stand they have stood ever since the Silurian epoch; but
+that long before that period, the world may have presented a wholly
+different aspect; and that the older continents, formed of formations older
+than any known to us, may now all be in a metamorphosed condition, or may
+lie buried under the ocean.
+</para>
+
+<para>
+Passing from these difficulties, all the other great leading facts in
+palaeontology seem to me simply to follow on the theory of descent with
+modification through natural selection.  We can thus understand how it is
+that new species come in slowly and successively; how species of different
+classes do not necessarily change together, or at the same rate, or in the
+same degree; yet in the long run that all undergo modification to some
+extent.  The extinction of old forms is the almost inevitable consequence
+of the production of new forms.  We can understand why when a species has
+once disappeared it never reappears.  Groups of species increase in numbers
+slowly, and endure for unequal periods of time; for the process of
+modification is necessarily slow, and depends on many complex
+contingencies.  The dominant species of the larger dominant groups tend to
+leave many modified descendants, and thus new sub-groups and groups are
+formed.  As these are formed, the species of the less vigorous groups, from
+their inferiority inherited from a common progenitor, tend to become
+extinct together, and to leave no modified offspring on the face of the
+earth.  But the utter extinction of a whole group of species may often be a
+very slow process, from the survival of a few descendants, lingering in
+protected and isolated situations.  When a group has once wholly
+disappeared, it does not reappear; for the link of generation has been
+broken.
+</para>
+
+<para>
+We can understand how the spreading of the dominant forms of life, which
+are those that oftenest vary, will in the long run tend to people the world
+with allied, but modified, descendants; and these will generally succeed in
+taking the places of those groups of species which are their inferiors in
+the struggle for existence.  Hence, after long intervals of time, the
+productions of the world will appear to have changed simultaneously.
+</para>
+
+<para>
+We can understand how it is that all the forms of life, ancient and recent,
+make together one grand system; for all are connected by generation.  We
+can understand, from the continued tendency to divergence of character, why
+the more ancient a form is, the more it generally differs from those now
+living.  Why ancient and extinct forms often tend to fill up gaps between
+existing forms, sometimes blending two groups previously classed as
+distinct into one; but more commonly only bringing them a little closer
+together.  The more ancient a form is, the more often, apparently, it
+displays characters in some degree intermediate between groups now
+distinct; for the more ancient a form is, the more nearly it will be
+related to, and consequently resemble, the common progenitor of groups,
+since become widely divergent.  Extinct forms are seldom directly
+intermediate between existing forms; but are intermediate only by a long
+and circuitous course through many extinct and very different forms.  We
+can clearly see why the organic remains of closely consecutive formations
+are more closely allied to each other, than are those of remote formations;
+for the forms are more closely linked together by generation:  we can
+clearly see why the remains of an intermediate formation are intermediate
+in character.
+</para>
+
+<para>
+The inhabitants of each successive period in the world's history have
+beaten their predecessors in the race for life, and are, in so far, higher
+in the scale of nature; and this may account for that vague yet ill-defined
+sentiment, felt by many palaeontologists, that organisation on the whole
+has progressed.  If it should hereafter be proved that ancient animals
+resemble to a certain extent the embryos of more recent animals of the same
+class, the fact will be intelligible.  The succession of the same types of
+structure within the same areas during the later geological periods ceases
+to be mysterious, and is simply explained by inheritance.
+</para>
+
+<para>
+If then the geological record be as imperfect as I believe it to be, and it
+may at least be asserted that the record cannot be proved to be much more
+perfect, the main objections to the theory of natural selection are greatly
+diminished or disappear.  On the other hand, all the chief laws of
+palaeontology plainly proclaim, as it seems to me, that species have been
+produced by ordinary generation:  old forms having been supplanted by new
+and improved forms of life, produced by the laws of variation still acting
+round us, and preserved by Natural Selection.
+</para>
+
+</chapter>
+
+<chapter>
+<chapheader>
+
+<chapnum>Chapter XI</chapnum>
+
+<title>Geographical Distribution</title>
+
+<chapsummary>
+Present distribution cannot be accounted for by differences in physical
+conditions -- Importance of barriers -- Affinity of the productions of the
+same continent -- Centres of creation -- Means of dispersal, by changes of
+climate and of the level of the land, and by occasional means -- Dispersal
+during the Glacial period co-extensive with the world.
+</chapsummary>
+</chapheader>
+
+<para>
+In considering the distribution of organic beings over the face of the
+globe, the first great fact which strikes us is, that neither the
+similarity nor the dissimilarity of the inhabitants of various regions can
+be accounted for by their climatal and other physical conditions.  Of late,
+almost every author who has studied the subject has come to this
+conclusion.  The case of America alone would almost suffice to prove its
+truth:  for if we exclude the northern parts where the circumpolar land is
+almost continuous, all authors agree that one of the most fundamental
+divisions in geographical distribution is that between the New and Old
+Worlds; yet if we travel over the vast American continent, from the central
+parts of the United States to its extreme southern point, we meet with the
+most diversified conditions; the most humid districts, arid deserts, lofty
+mountains, grassy plains, forests, marshes, lakes, and great rivers, under
+almost every temperature.  There is hardly a climate or condition in the
+Old World which cannot be paralleled in the New--at least as closely as the
+same species generally require; for it is a most rare case to find a group
+of organisms confined to any small spot, having conditions peculiar in only
+a slight degree; for instance, small areas in the Old World could be
+pointed out hotter than any in the New World, yet these are not inhabited
+by a peculiar fauna or flora.  Notwithstanding this parallelism in the
+conditions of the Old and New Worlds, how widely different are their living
+productions!
+</para>
+
+<para>
+In the southern hemisphere, if we compare large tracts of land in
+Australia, South Africa, and western South America, between latitudes 25
+deg and 35 deg, we shall find parts extremely similar in all their
+conditions, yet it would not be possible to point out three faunas and
+floras more utterly dissimilar.  Or again we may compare the productions of
+South America south of lat. 35 deg with those north of 25 deg, which
+consequently inhabit a considerably different climate, and they will be
+found incomparably more closely related to each other, than they are to the
+productions of Australia or Africa under nearly the same climate. 
+Analogous facts could be given with respect to the inhabitants of the sea.
+</para>
+
+<para>
+A second great fact which strikes us in our general review is, that
+barriers of any kind, or obstacles to free migration, are related in a
+close and important manner to the differences between the productions of
+various regions.  We see this in the great difference of nearly all the
+terrestrial productions of the New and Old Worlds, excepting in the
+northern parts, where the land almost joins, and where, under a slightly
+different climate, there might have been free migration for the northern
+temperate forms, as there now is for the strictly arctic productions.  We
+see the same fact in the great difference between the inhabitants of
+Australia, Africa, and South America under the same latitude:  for these
+countries are almost as much isolated from each other as is possible.  On
+each continent, also, we see the same fact; for on the opposite sides of
+lofty and continuous mountain-ranges, and of great deserts, and sometimes
+even of large rivers, we find different productions; though as mountain
+chains, deserts, &amp;c., are not as impassable, or likely to have endured so
+long as the oceans separating continents, the differences are very inferior
+in degree to those characteristic of distinct continents.
+</para>
+
+<para>
+Turning to the sea, we find the same law.  No two marine faunas are more
+distinct, with hardly a fish, shell, or crab in common, than those of the
+eastern and western shores of South and Central America; yet these great
+faunas are separated only by the narrow, but impassable, isthmus of Panama. 
+Westward of the shores of America, a wide space of open ocean extends, with
+not an island as a halting-place for emigrants; here we have a barrier of
+another kind, and as soon as this is passed we meet in the eastern islands
+of the Pacific, with another and totally distinct fauna.  So that here
+three marine faunas range far northward and southward, in parallel lines
+not far from each other, under corresponding climates; but from being
+separated from each other by impassable barriers, either of land or open
+sea, they are wholly distinct.  On the other hand, proceeding still further
+westward from the eastern islands of the tropical parts of the Pacific, we
+encounter no impassable barriers, and we have innumerable islands as
+halting-places, until after travelling over a hemisphere we come to the
+shores of Africa; and over this vast space we meet with no well-defined and
+distinct marine faunas.  Although hardly one shell, crab or fish is common
+to the above-named three approximate faunas of Eastern and Western America
+and the eastern Pacific islands, yet many fish range from the Pacific into
+the Indian Ocean, and many shells are common to the eastern islands of the
+Pacific and the eastern shores of Africa, on almost exactly opposite
+meridians of longitude.
+</para>
+
+<para>
+A third great fact, partly included in the foregoing statements, is the
+affinity of the productions of the same continent or sea, though the
+species themselves are distinct at different points and stations.  It is a
+law of the widest generality, and every continent offers innumerable
+instances.  Nevertheless the naturalist in travelling, for instance, from
+north to south never fails to be struck by the manner in which successive
+groups of beings, specifically distinct, yet clearly related, replace each
+other.  He hears from closely allied, yet distinct kinds of birds, notes
+nearly similar, and sees their nests similarly constructed, but not quite
+alike, with eggs coloured in nearly the same manner.  The plains near the
+Straits of Magellan are inhabited by one species of Rhea (American
+ostrich), and northward the plains of La Plata by another species of the
+same genus; and not by a true ostrich or emeu, like those found in Africa
+and Australia under the same latitude.  On these same plains of La Plata,
+we see the agouti and bizcacha, animals having nearly the same habits as
+our hares and rabbits and belonging to the same order of Rodents, but they
+plainly display an American type of structure.  We ascend the lofty peaks
+of the Cordillera and we find an alpine species of bizcacha; we look to the
+waters, and we do not find the beaver or musk-rat, but the coypu and
+capybara, rodents of the American type.  Innumerable other instances could
+be given.  If we look to the islands off the American shore, however much
+they may differ in geological structure, the inhabitants, though they may
+be all peculiar species, are essentially American.  We may look back to
+past ages, as shown in the last chapter, and we find American types then
+prevalent on the American continent and in the American seas.  We see in
+these facts some deep organic bond, prevailing throughout space and time,
+over the same areas of land and water, and independent of their physical
+conditions.  The naturalist must feel little curiosity, who is not led to
+inquire what this bond is.
+</para>
+
+<para>
+This bond, on my theory, is simply inheritance, that cause which alone, as
+far as we positively know, produces organisms quite like, or, as we see in
+the case of varieties nearly like each other.  The dissimilarity of the
+inhabitants of different regions may be attributed to modification through
+natural selection, and in a quite subordinate degree to the direct
+influence of different physical conditions.  The degree of dissimilarity
+will depend on the migration of the more dominant forms of life from one
+region into another having been effected with more or less ease, at periods
+more or less remote;--on the nature and number of the former
+immigrants;--and on their action and reaction, in their mutual struggles
+for life;--the relation of organism to organism being, as I have already
+often remarked, the most important of all relations.  Thus the high
+importance of barriers comes into play by checking migration; as does time
+for the slow process of modification through natural selection. 
+Widely-ranging species, abounding in individuals, which have already
+triumphed over many competitors in their own widely-extended homes will
+have the best chance of seizing on new places, when they spread into new
+countries.  In their new homes they will be exposed to new conditions, and
+will frequently undergo further modification and improvement; and thus they
+will become still further victorious, and will produce groups of modified
+descendants.  On this principle of inheritance with modification, we can
+understand how it is that sections of genera, whole genera, and even
+families are confined to the same areas, as is so commonly and notoriously
+the case.
+</para>
+
+<para>
+I believe, as was remarked in the last chapter, in no law of necessary
+development.  As the variability of each species is an independent
+property, and will be taken advantage of by natural selection, only so far
+as it profits the individual in its complex struggle for life, so the
+degree of modification in different species will be no uniform quantity. 
+If, for instance, a number of species, which stand in direct competition
+with each other, migrate in a body into a new and afterwards isolated
+country, they will be little liable to modification; for neither migration
+nor isolation in themselves can do anything.  These principles come into
+play only by bringing organisms into new relations with each other, and in
+a lesser degree with the surrounding physical conditions.  As we have seen
+in the last chapter that some forms have retained nearly the same character
+from an enormously remote geological period, so certain species have
+migrated over vast spaces, and have not become greatly modified.
+</para>
+
+<para>
+On these views, it is obvious, that the several species of the same genus,
+though inhabiting the most distant quarters of the world, must originally
+have proceeded from the same source, as they have descended from the same
+progenitor.  In the case of those species, which have undergone during
+whole geological periods but little modification, there is not much
+difficulty in believing that they may have migrated from the same region;
+for during the vast geographical and climatal changes which will have
+supervened since ancient times, almost any amount of migration is possible. 
+But in many other cases, in which we have reason to believe that the
+species of a genus have been produced within comparatively recent times,
+there is great difficulty on this head.  It is also obvious that the
+individuals of the same species, though now inhabiting distant and isolated
+regions, must have proceeded from one spot, where their parents were first
+produced:  for, as explained in the last chapter, it is incredible that
+individuals identically the same should ever have been produced through
+natural selection from parents specifically distinct.
+</para>
+
+<para>
+We are thus brought to the question which has been largely discussed by
+naturalists, namely, whether species have been created at one or more
+points of the earth's surface.  Undoubtedly there are very many cases of
+extreme difficulty, in understanding how the same species could possibly
+have migrated from some one point to the several distant and isolated
+points, where now found.  Nevertheless the simplicity of the view that each
+species was first produced within a single region captivates the mind.  He
+who rejects it, rejects the vera causa of ordinary generation with
+subsequent migration, and calls in the agency of a miracle.  It is
+universally admitted, that in most cases the area inhabited by a species is
+continuous; and when a plant or animal inhabits two points so distant from
+each other, or with an interval of such a nature, that the space could not
+be easily passed over by migration, the fact is given as something
+remarkable and exceptional.  The capacity of migrating across the sea is
+more distinctly limited in terrestrial mammals, than perhaps in any other
+organic beings; and, accordingly, we find no inexplicable cases of the same
+mammal inhabiting distant points of the world.  No geologist will feel any
+difficulty in such cases as Great Britain having been formerly united to
+Europe, and consequently possessing the same quadrupeds.  But if the same
+species can be produced at two separate points, why do we not find a single
+mammal common to Europe and Australia or South America?  The conditions of
+life are nearly the same, so that a multitude of European animals and
+plants have become naturalised in America and Australia; and some of the
+aboriginal plants are identically the same at these distant points of the
+northern and southern hemispheres?  The answer, as I believe, is, that
+mammals have not been able to migrate, whereas some plants, from their
+varied means of dispersal, have migrated across the vast and broken
+interspace.  The great and striking influence which barriers of every kind
+have had on distribution, is intelligible only on the view that the great
+majority of species have been produced on one side alone, and have not been
+able to migrate to the other side.  Some few families, many sub-families,
+very many genera, and a still greater number of sections of genera are
+confined to a single region; and it has been observed by several
+naturalists, that the most natural genera, or those genera in which the
+species are most closely related to each other, are generally local, or
+confined to one area.  What a strange anomaly it would be, if, when coming
+one step lower in the series, to the individuals of the same species, a
+directly opposite rule prevailed; and species were not local, but had been
+produced in two or more distinct areas!
+</para>
+
+<para>
+Hence it seems to me, as it has to many other naturalists, that the view of
+each species having been produced in one area alone, and having
+subsequently migrated from that area as far as its powers of migration and
+subsistence under past and present conditions permitted, is the most
+probable.  Undoubtedly many cases occur, in which we cannot explain how the
+same species could have passed from one point to the other.  But the
+geographical and climatal changes, which have certainly occurred within
+recent geological times, must have interrupted or rendered discontinuous
+the formerly continuous range of many species.  So that we are reduced to
+consider whether the exceptions to continuity of range are so numerous and
+of so grave a nature, that we ought to give up the belief, rendered
+probable by general considerations, that each species has been produced
+within one area, and has migrated thence as far as it could.  It would be
+hopelessly tedious to discuss all the exceptional cases of the same
+species, now living at distant and separated points; nor do I for a moment
+pretend that any explanation could be offered of many such cases.  But
+after some preliminary remarks, I will discuss a few of the most striking
+classes of facts; namely, the existence of the same species on the summits
+of distant mountain-ranges, and at distant points in the arctic and
+antarctic regions; and secondly (in the following chapter), the wide
+distribution of freshwater productions; and thirdly, the occurrence of the
+same terrestrial species on islands and on the mainland, though separated
+by hundreds of miles of open sea.  If the existence of the same species at
+distant and isolated points of the earth's surface, can in many instances
+be explained on the view of each species having migrated from a single
+birthplace; then, considering our ignorance with respect to former climatal
+and geographical changes and various occasional means of transport, the
+belief that this has been the universal law, seems to me incomparably the
+safest.
+</para>
+
+<para>
+In discussing this subject, we shall be enabled at the same time to
+consider a point equally important for us, namely, whether the several
+distinct species of a genus, which on my theory have all descended from a
+common progenitor, can have migrated (undergoing modification during some
+part of their migration) from the area inhabited by their progenitor.  If
+it can be shown to be almost invariably the case, that a region, of which
+most of its inhabitants are closely related to, or belong to the same
+genera with the species of a second region, has probably received at some
+former period immigrants from this other region, my theory will be
+strengthened; for we can clearly understand, on the principle of
+modification, why the inhabitants of a region should be related to those of
+another region, whence it has been stocked.  A volcanic island, for
+instance, upheaved and formed at the distance of a few hundreds of miles
+from a continent, would probably receive from it in the course of time a
+few colonists, and their descendants, though modified, would still be
+plainly related by inheritance to the inhabitants of the continent.  Cases
+of this nature are common, and are, as we shall hereafter more fully see,
+inexplicable on the theory of independent creation.  This view of the
+relation of species in one region to those in another, does not differ much
+(by substituting the word variety for species) from that lately advanced in
+an ingenious paper by Mr. Wallace, in which he concludes, that 'every
+species has come into existence coincident both in space and time with a
+pre-existing closely allied species.'  And I now know from correspondence,
+that this coincidence he attributes to generation with modification.
+</para>
+
+<para>
+The previous remarks on 'single and multiple centres of creation' do not
+directly bear on another allied question,--namely whether all the
+individuals of the same species have descended from a single pair, or
+single hermaphrodite, or whether, as some authors suppose, from many
+individuals simultaneously created.  With those organic beings which never
+intercross (if such exist), the species, on my theory, must have descended
+from a succession of improved varieties, which will never have blended with
+other individuals or varieties, but will have supplanted each other; so
+that, at each successive stage of modification and improvement, all the
+individuals of each variety will have descended from a single parent.  But
+in the majority of cases, namely, with all organisms which habitually unite
+for each birth, or which often intercross, I believe that during the slow
+process of modification the individuals of the species will have been kept
+nearly uniform by intercrossing; so that many individuals will have gone on
+simultaneously changing, and the whole amount of modification will not have
+been due, at each stage, to descent from a single parent.  To illustrate
+what I mean:  our English racehorses differ slightly from the horses of
+every other breed; but they do not owe their difference and superiority to
+descent from any single pair, but to continued care in selecting and
+training many individuals during many generations.
+</para>
+
+<para>
+Before discussing the three classes of facts, which I have selected as
+presenting the greatest amount of difficulty on the theory of 'single
+centres of creation,' I must say a few words on the means of dispersal.
+</para>
+
+<para>
+Means of Dispersal. -- Sir C. Lyell and other authors have ably treated
+this subject.  I can give here only the briefest abstract of the more
+important facts.  Change of climate must have had a powerful influence on
+migration:  a region when its climate was different may have been a high
+road for migration, but now be impassable; I shall, however, presently have
+to discuss this branch of the subject in some detail.  Changes of level in
+the land must also have been highly influential:  a narrow isthmus now
+separates two marine faunas; submerge it, or let it formerly have been
+submerged, and the two faunas will now blend or may formerly have blended: 
+where the sea now extends, land may at a former period have connected
+islands or possibly even continents together, and thus have allowed
+terrestrial productions to pass from one to the other.  No geologist will
+dispute that great mutations of level have occurred within the period of
+existing organisms.  Edward Forbes insisted that all the islands in the
+Atlantic must recently have been connected with Europe or Africa, and
+Europe likewise with America.  Other authors have thus hypothetically
+bridged over every ocean, and have united almost every island to some
+mainland.  If indeed the arguments used by Forbes are to be trusted, it
+must be admitted that scarcely a single island exists which has not
+recently been united to some continent.  This view cuts the Gordian knot of
+the dispersal of the same species to the most distant points, and removes
+many a difficulty:  but to the best of any judgment we are not authorized
+in admitting such enormous geographical changes within the period of
+existing species.  It seems to me that we have abundant evidence of great
+oscillations of level in our continents; but not of such vast changes in
+their position and extension, as to have united them within the recent
+period to each other and to the several intervening oceanic islands.  I
+freely admit the former existence of many islands, now buried beneath the
+sea, which may have served as halting places for plants and for many
+animals during their migration.  In the coral-producing oceans such sunken
+islands are now marked, as I believe, by rings of coral or atolls standing
+over them.  Whenever it is fully admitted, as I believe it will some day
+be, that each species has proceeded from a single birthplace, and when in
+the course of time we know something definite about the means of
+distribution, we shall be enabled to speculate with security on the former
+extension of the land.  But I do not believe that it will ever be proved
+that within the recent period continents which are now quite separate, have
+been continuously, or almost continuously, united with each other, and with
+the many existing oceanic islands.  Several facts in distribution,--such as
+the great difference in the marine faunas on the opposite sides of almost
+every continent,--the close relation of the tertiary inhabitants of several
+lands and even seas to their present inhabitants,--a certain degree of
+relation (as we shall hereafter see) between the distribution of mammals
+and the depth of the sea,--these and other such facts seem to me opposed to
+the admission of such prodigious geographical revolutions within the recent
+period, as are necessitated on the view advanced by Forbes and admitted by
+his many followers.  The nature and relative proportions of the inhabitants
+of oceanic islands likewise seem to me opposed to the belief of their
+former continuity with continents.  Nor does their almost universally
+volcanic composition favour the admission that they are the wrecks of
+sunken continents;--if they had originally existed as mountain-ranges on
+the land, some at least of the islands would have been formed, like other
+mountain-summits, of granite, metamorphic schists, old fossiliferous or
+other such rocks, instead of consisting of mere piles of volcanic matter.
+</para>
+
+<para>
+I must now say a few words on what are called accidental means, but which
+more properly might be called occasional means of distribution.  I shall
+here confine myself to plants.  In botanical works, this or that plant is
+stated to be ill adapted for wide dissemination; but for transport across
+the sea, the greater or less facilities may be said to be almost wholly
+unknown.  Until I tried, with Mr. Berkeley's aid, a few experiments, it was
+not even known how far seeds could resist the injurious action of
+sea-water.  To my surprise I found that out of 87 kinds, 64 germinated
+after an immersion of 28 days, and a few survived an immersion of 137 days. 
+For convenience sake I chiefly tried small seeds, without the capsule or
+fruit; and as all of these sank in a few days, they could not be floated
+across wide spaces of the sea, whether or not they were injured by the
+salt-water.  Afterwards I tried some larger fruits, capsules, &amp;c., and some
+of these floated for a long time.  It is well known what a difference there
+is in the buoyancy of green and seasoned timber; and it occurred to me that
+floods might wash down plants or branches, and that these might be dried on
+the banks, and then by a fresh rise in the stream be washed into the sea. 
+Hence I was led to dry stems and branches of 94 plants with ripe fruit, and
+to place them on sea water.  The majority sank quickly, but some which
+whilst green floated for a very short time, when dried floated much longer;
+for instance, ripe hazel-nuts sank immediately, but when dried, they
+floated for 90 days and afterwards when planted they germinated; an
+asparagus plant with ripe berries floated for 23 days, when dried it
+floated for 85 days, and the seeds afterwards germinated:  the ripe seeds
+of Helosciadium sank in two days, when dried they floated for above 90
+days, and afterwards germinated.  Altogether out of the 94 dried plants, 18
+floated for above 28 days, and some of the 18 floated for a very much
+longer period.  So that as 64/87 seeds germinated after an immersion of 28
+days; and as 18/94 plants with ripe fruit (but not all the same species as
+in the foregoing experiment) floated, after being dried, for above 28 days,
+as far as we may infer anything from these scanty facts, we may conclude
+that the seeds of 14/100 plants of any country might be floated by
+sea-currents during 28 days, and would retain their power of germination. 
+In Johnston's Physical Atlas, the average rate of the several Atlantic
+currents is 33 miles per diem (some currents running at the rate of 60
+miles per diem); on this average, the seeds of 14/100 plants belonging to
+one country might be floated across 924 miles of sea to another country;
+and when stranded, if blown to a favourable spot by an inland gale, they
+would germinate.
+</para>
+
+<para>
+Subsequently to my experiments, M. Martens tried similar ones, but in a
+much better manner, for he placed the seeds in a box in the actual sea, so
+that they were alternately wet and exposed to the air like really floating
+plants.  He tried 98 seeds, mostly different from mine; but he chose many
+large fruits and likewise seeds from plants which live near the sea; and
+this would have favoured the average length of their flotation and of their
+resistance to the injurious action of the salt-water.  On the other hand he
+did not previously dry the plants or branches with the fruit; and this, as
+we have seen, would have caused some of them to have floated much longer. 
+The result was that 18/98 of his seeds floated for 42 days, and were then
+capable of germination.  But I do not doubt that plants exposed to the
+waves would float for a less time than those protected from violent
+movement as in our experiments.  Therefore it would perhaps be safer to
+assume that the seeds of about 10/100 plants of a flora, after having been
+dried, could be floated across a space of sea 900 miles in width, and would
+then germinate.  The fact of the larger fruits often floating longer than
+the small, is interesting; as plants with large seeds or fruit could hardly
+be transported by any other means; and Alph. de Candolle has shown that
+such plants generally have restricted ranges.
+</para>
+
+<para>
+But seeds may be occasionally transported in another manner.  Drift timber
+is thrown up on most islands, even on those in the midst of the widest
+oceans; and the natives of the coral-islands in the Pacific, procure stones
+for their tools, solely from the roots of drifted trees, these stones being
+a valuable royal tax.  I find on examination, that when irregularly shaped
+stones are embedded in the roots of trees, small parcels of earth are very
+frequently enclosed in their interstices and behind them,--so perfectly
+that not a particle could be washed away in the longest transport:  out of
+one small portion of earth thus completely enclosed by wood in an oak about
+50 years old, three dicotyledonous plants germinated:  I am certain of the
+accuracy of this observation.  Again, I can show that the carcasses of
+birds, when floating on the sea, sometimes escape being immediately
+devoured; and seeds of many kinds in the crops of floating birds long
+retain their vitality:  peas and vetches, for instance, are killed by even
+a few days' immersion in sea-water; but some taken out of the crop of a
+pigeon, which had floated on artificial salt-water for 30 days, to my
+surprise nearly all germinated.
+</para>
+
+<para>
+Living birds can hardly fail to be highly effective agents in the
+transportation of seeds.  I could give many facts showing how frequently
+birds of many kinds are blown by gales to vast distances across the ocean. 
+We may I think safely assume that under such circumstances their rate of
+flight would often be 35 miles an hour; and some authors have given a far
+higher estimate.  I have never seen an instance of nutritious seeds passing
+through the intestines of a bird; but hard seeds of fruit will pass
+uninjured through even the digestive organs of a turkey.  In the course of
+two months, I picked up in my garden 12 kinds of seeds, out of the
+excrement of small birds, and these seemed perfect, and some of them, which
+I tried, germinated.  But the following fact is more important:  the crops
+of birds do not secrete gastric juice, and do not in the least injure, as I
+know by trial, the germination of seeds; now after a bird has found and
+devoured a large supply of food, it is positively asserted that all the
+grains do not pass into the gizzard for 12 or even 18 hours.  A bird in
+this interval might easily be blown to the distance of 500 miles, and hawks
+are known to look out for tired birds, and the contents of their torn crops
+might thus readily get scattered.  Mr. Brent informs me that a friend of
+his had to give up flying carrier-pigeons from France to England, as the
+hawks on the English coast destroyed so many on their arrival.  Some hawks
+and owls bolt their prey whole, and after an interval of from twelve to
+twenty hours, disgorge pellets, which, as I know from experiments made in
+the Zoological Gardens, include seeds capable of germination.  Some seeds
+of the oat, wheat, millet, canary, hemp, clover, and beet germinated after
+having been from twelve to twenty-one hours in the stomachs of different
+birds of prey; and two seeds of beet grew after having been thus retained
+for two days and fourteen hours.  Freshwater fish, I find, eat seeds of
+many land and water plants:  fish are frequently devoured by birds, and
+thus the seeds might be transported from place to place.  I forced many
+kinds of seeds into the stomachs of dead fish, and then gave their bodies
+to fishing-eagles, storks, and pelicans; these birds after an interval of
+many hours, either rejected the seeds in pellets or passed them in their
+excrement; and several of these seeds retained their power of germination. 
+Certain seeds, however, were always killed by this process.
+</para>
+
+<para>
+Although the beaks and feet of birds are generally quite clean, I can show
+that earth sometimes adheres to them:  in one instance I removed twenty-two
+grains of dry argillaceous earth from one foot of a partridge, and in this
+earth there was a pebble quite as large as the seed of a vetch.  Thus seeds
+might occasionally be transported to great distances; for many facts could
+be given showing that soil almost everywhere is charged with seeds. 
+Reflect for a moment on the millions of quails which annually cross the
+Mediterranean; and can we doubt that the earth adhering to their feet would
+sometimes include a few minute seeds?  But I shall presently have to recur
+to this subject.
+</para>
+
+<para>
+As icebergs are known to be sometimes loaded with earth and stones, and
+have even carried brushwood, bones, and the nest of a land-bird, I can
+hardly doubt that they must occasionally have transported seeds from one
+part to another of the arctic and antarctic regions, as suggested by Lyell;
+and during the Glacial period from one part of the now temperate regions to
+another.  In the Azores, from the large number of the species of plants
+common to Europe, in comparison with the plants of other oceanic islands
+nearer to the mainland, and (as remarked by Mr. H. C. Watson) from the
+somewhat northern character of the flora in comparison with the latitude, I
+suspected that these islands had been partly stocked by ice-borne seeds,
+during the Glacial epoch.  At my request Sir C. Lyell wrote to M. Hartung
+to inquire whether he had observed erratic boulders on these islands, and
+he answered that he had found large fragments of granite and other rocks,
+which do not occur in the archipelago.  Hence we may safely infer that
+icebergs formerly landed their rocky burthens on the shores of these
+mid-ocean islands, and it is at least possible that they may have brought
+thither the seeds of northern plants.
+</para>
+
+<para>
+Considering that the several above means of transport, and that several
+other means, which without doubt remain to be discovered, have been in
+action year after year, for centuries and tens of thousands of years, it
+would I think be a marvellous fact if many plants had not thus become
+widely transported.  These means of transport are sometimes called
+accidental, but this is not strictly correct:  the currents of the sea are
+not accidental, nor is the direction of prevalent gales of wind.  It should
+be observed that scarcely any means of transport would carry seeds for very
+great distances; for seeds do not retain their vitality when exposed for a
+great length of time to the action of seawater; nor could they be long
+carried in the crops or intestines of birds.  These means, however, would
+suffice for occasional transport across tracts of sea some hundred miles in
+breadth, or from island to island, or from a continent to a neighbouring
+island, but not from one distant continent to another.  The floras of
+distant continents would not by such means become mingled in any great
+degree; but would remain as distinct as we now see them to be.  The
+currents, from their course, would never bring seeds from North America to
+Britain, though they might and do bring seeds from the West Indies to our
+western shores, where, if not killed by so long an immersion in salt-water,
+they could not endure our climate.  Almost every year, one or two
+land-birds are blown across the whole Atlantic Ocean, from North America to
+the western shores of Ireland and England; but seeds could be transported
+by these wanderers only by one means, namely, in dirt sticking to their
+feet, which is in itself a rare accident.  Even in this case, how small
+would the chance be of a seed falling on favourable soil, and coming to
+maturity!  But it would be a great error to argue that because a
+well-stocked island, like Great Britain, has not, as far as is known (and
+it would be very difficult to prove this), received within the last few
+centuries, through occasional means of transport, immigrants from Europe or
+any other continent, that a poorly-stocked island, though standing more
+remote from the mainland, would not receive colonists by similar means.  I
+do not doubt that out of twenty seeds or animals transported to an island,
+even if far less well-stocked than Britain, scarcely more than one would be
+so well fitted to its new home, as to become naturalised.  But this, as it
+seems to me, is no valid argument against what would be effected by
+occasional means of transport, during the long lapse of geological time,
+whilst an island was being upheaved and formed, and before it had become
+fully stocked with inhabitants.  On almost bare land, with few or no
+destructive insects or birds living there, nearly every seed, which chanced
+to arrive, would be sure to germinate and survive.
+</para>
+
+<para>
+Dispersal during the Glacial period. -- The identity of many plants and
+animals, on mountain-summits, separated from each other by hundreds of
+miles of lowlands, where the Alpine species could not possibly exist, is
+one of the most striking cases known of the same species living at distant
+points, without the apparent possibility of their having migrated from one
+to the other.  It is indeed a remarkable fact to see so many of the same
+plants living on the snowy regions of the Alps or Pyrenees, and in the
+extreme northern parts of Europe; but it is far more remarkable, that the
+plants on the White Mountains, in the United States of America, are all the
+same with those of Labrador, and nearly all the same, as we hear from Asa
+Gray, with those on the loftiest mountains of Europe.  Even as long ago as
+1747, such facts led Gmelin to conclude that the same species must have
+been independently created at several distinct points; and we might have
+remained in this same belief, had not Agassiz and others called vivid
+attention to the Glacial period, which, as we shall immediately see,
+affords a simple explanation of these facts.  We have evidence of almost
+every conceivable kind, organic and inorganic, that within a very recent
+geological period, central Europe and North America suffered under an
+Arctic climate.  The ruins of a house burnt by fire do not tell their tale
+more plainly, than do the mountains of Scotland and Wales, with their
+scored flanks, polished surfaces, and perched boulders, of the icy streams
+with which their valleys were lately filled.  So greatly has the climate of
+Europe changed, that in Northern Italy, gigantic moraines, left by old
+glaciers, are now clothed by the vine and maize.  Throughout a large part
+of the United States, erratic boulders, and rocks scored by drifted
+icebergs and coast-ice, plainly reveal a former cold period.
+</para>
+
+<para>
+The former influence of the glacial climate on the distribution of the
+inhabitants of Europe, as explained with remarkable clearness by Edward
+Forbes, is substantially as follows.  But we shall follow the changes more
+readily, by supposing a new glacial period to come slowly on, and then pass
+away, as formerly occurred.  As the cold came on, and as each more southern
+zone became fitted for arctic beings and ill-fitted for their former more
+temperate inhabitants, the latter would be supplanted and arctic
+productions would take their places.  The inhabitants of the more temperate
+regions would at the same time travel southward, unless they were stopped
+by barriers, in which case they would perish.  The mountains would become
+covered with snow and ice, and their former Alpine inhabitants would
+descend to the plains.  By the time that the cold had reached its maximum,
+we should have a uniform arctic fauna and flora, covering the central parts
+of Europe, as far south as the Alps and Pyrenees, and even stretching into
+Spain.  The now temperate regions of the United States would likewise be
+covered by arctic plants and animals, and these would be nearly the same
+with those of Europe; for the present circumpolar inhabitants, which we
+suppose to have everywhere travelled southward, are remarkably uniform
+round the world.  We may suppose that the Glacial period came on a little
+earlier or later in North America than in Europe, so will the southern
+migration there have been a little earlier or later; but this will make no
+difference in the final result.
+</para>
+
+<para>
+As the warmth returned, the arctic forms would retreat northward, closely
+followed up in their retreat by the productions of the more temperate
+regions.  And as the snow melted from the bases of the mountains, the
+arctic forms would seize on the cleared and thawed ground, always ascending
+higher and higher, as the warmth increased, whilst their brethren were
+pursuing their northern journey.  Hence, when the warmth had fully
+returned, the same arctic species, which had lately lived in a body
+together on the lowlands of the Old and New Worlds, would be left isolated
+on distant mountain-summits (having been exterminated on all lesser
+heights) and in the arctic regions of both hemispheres.
+</para>
+
+<para>
+Thus we can understand the identity of many plants at points so immensely
+remote as on the mountains of the United States and of Europe.  We can thus
+also understand the fact that the Alpine plants of each mountain-range are
+more especially related to the arctic forms living due north or nearly due
+north of them:  for the migration as the cold came on, and the re-migration
+on the returning warmth, will generally have been due south and north.  The
+Alpine plants, for example, of Scotland, as remarked by Mr. H. C. Watson,
+and those of the Pyrenees, as remarked by Ramond, are more especially
+allied to the plants of northern Scandinavia; those of the United States to
+Labrador; those of the mountains of Siberia to the arctic regions of that
+country.  These views, grounded as they are on the perfectly
+well-ascertained occurrence of a former Glacial period, seem to me to
+explain in so satisfactory a manner the present distribution of the Alpine
+and Arctic productions of Europe and America, that when in other regions we
+find the same species on distant mountain-summits, we may almost conclude
+without other evidence, that a colder climate permitted their former
+migration across the low intervening tracts, since become too warm for
+their existence.
+</para>
+
+<para>
+If the climate, since the Glacial period, has ever been in any degree
+warmer than at present (as some geologists in the United States believe to
+have been the case, chiefly from the distribution of the fossil Gnathodon),
+then the arctic and temperate productions will at a very late period have
+marched a little further north, and subsequently have retreated to their
+present homes; but I have met with no satisfactory evidence with respect to
+this intercalated slightly warmer period, since the Glacial period.
+</para>
+
+<para>
+The arctic forms, during their long southern migration and re-migration
+northward, will have been exposed to nearly the same climate, and, as is
+especially to be noticed, they will have kept in a body together;
+consequently their mutual relations will not have been much disturbed, and,
+in accordance with the principles inculcated in this volume, they will not
+have been liable to much modification.  But with our Alpine productions,
+left isolated from the moment of the returning warmth, first at the bases
+and ultimately on the summits of the mountains, the case will have been
+somewhat different; for it is not likely that all the same arctic species
+will have been left on mountain ranges distant from each other, and have
+survived there ever since; they will, also, in all probability have become
+mingled with ancient Alpine species, which must have existed on the
+mountains before the commencement of the Glacial epoch, and which during
+its coldest period will have been temporarily driven down to the plains;
+they will, also, have been exposed to somewhat different climatal
+influences.  Their mutual relations will thus have been in some degree
+disturbed; consequently they will have been liable to modification; and
+this we find has been the case; for if we compare the present Alpine plants
+and animals of the several great European mountain-ranges, though very many
+of the species are identically the same, some present varieties, some are
+ranked as doubtful forms, and some few are distinct yet closely allied or
+representative species.
+</para>
+
+<para>
+In illustrating what, as I believe, actually took place during the Glacial
+period, I assumed that at its commencement the arctic productions were as
+uniform round the polar regions as they are at the present day.  But the
+foregoing remarks on distribution apply not only to strictly arctic forms,
+but also to many sub-arctic and to some few northern temperate forms, for
+some of these are the same on the lower mountains and on the plains of
+North America and Europe; and it may be reasonably asked how I account for
+the necessary degree of uniformity of the sub-arctic and northern temperate
+forms round the world, at the commencement of the Glacial period.  At the
+present day, the sub-arctic and northern temperate productions of the Old
+and New Worlds are separated from each other by the Atlantic Ocean and by
+the extreme northern part of the Pacific.  During the Glacial period, when
+the inhabitants of the Old and New Worlds lived further southwards than at
+present, they must have been still more completely separated by wider
+spaces of ocean.  I believe the above difficulty may be surmounted by
+looking to still earlier changes of climate of an opposite nature.  We have
+good reason to believe that during the newer Pliocene period, before the
+Glacial epoch, and whilst the majority of the inhabitants of the world were
+specifically the same as now, the climate was warmer than at the present
+day.  Hence we may suppose that the organisms now living under the climate
+of latitude 60 deg, during the Pliocene period lived further north under
+the Polar Circle, in latitude 66 deg-67 deg; and that the strictly arctic
+productions then lived on the broken land still nearer to the pole.  Now if
+we look at a globe, we shall see that under the Polar Circle there is
+almost continuous land from western Europe, through Siberia, to eastern
+America.  And to this continuity of the circumpolar land, and to the
+consequent freedom for intermigration under a more favourable climate, I
+attribute the necessary amount of uniformity in the sub-arctic and northern
+temperate productions of the Old and New Worlds, at a period anterior to
+the Glacial epoch.
+</para>
+
+<para>
+Believing, from reasons before alluded to, that our continents have long
+remained in nearly the same relative position, though subjected to large,
+but partial oscillations of level, I am strongly inclined to extend the
+above view, and to infer that during some earlier and still warmer period,
+such as the older Pliocene period, a large number of the same plants and
+animals inhabited the almost continuous circumpolar land; and that these
+plants and animals, both in the Old and New Worlds, began slowly to migrate
+southwards as the climate became less warm, long before the commencement of
+the Glacial period.  We now see, as I believe, their descendants, mostly in
+a modified condition, in the central parts of Europe and the United States. 
+On this view we can understand the relationship, with very little identity,
+between the productions of North America and Europe,--a relationship which
+is most remarkable, considering the distance of the two areas, and their
+separation by the Atlantic Ocean.  We can further understand the singular
+fact remarked on by several observers, that the productions of Europe and
+America during the later tertiary stages were more closely related to each
+other than they are at the present time; for during these warmer periods
+the northern parts of the Old and New Worlds will have been almost
+continuously united by land, serving as a bridge, since rendered impassable
+by cold, for the inter-migration of their inhabitants.
+</para>
+
+<para>
+During the slowly decreasing warmth of the Pliocene period, as soon as the
+species in common, which inhabited the New and Old Worlds, migrated south
+of the Polar Circle, they must have been completely cut off from each
+other.  This separation, as far as the more temperate productions are
+concerned, took place long ages ago.  And as the plants and animals
+migrated southward, they will have become mingled in the one great region
+with the native American productions, and have had to compete with them;
+and in the other great region, with those of the Old World.  Consequently
+we have here everything favourable for much modification,--for far more
+modification than with the Alpine productions, left isolated, within a much
+more recent period, on the several mountain-ranges and on the arctic lands
+of the two Worlds.  Hence it has come, that when we compare the now living
+productions of the temperate regions of the New and Old Worlds, we find
+very few identical species (though Asa Gray has lately shown that more
+plants are identical than was formerly supposed), but we find in every
+great class many forms, which some naturalists rank as geographical races,
+and others as distinct species; and a host of closely allied or
+representative forms which are ranked by all naturalists as specifically
+distinct.
+</para>
+
+<para>
+As on the land, so in the waters of the sea, a slow southern migration of a
+marine fauna, which during the Pliocene or even a somewhat earlier period,
+was nearly uniform along the continuous shores of the Polar Circle, will
+account, on the theory of modification, for many closely allied forms now
+living in areas completely sundered.  Thus, I think, we can understand the
+presence of many existing and tertiary representative forms on the eastern
+and western shores of temperate North America; and the still more striking
+case of many closely allied crustaceans (as described in Dana's admirable
+work), of some fish and other marine animals, in the Mediterranean and in
+the seas of Japan,--areas now separated by a continent and by nearly a
+hemisphere of equatorial ocean.
+</para>
+
+<para>
+These cases of relationship, without identity, of the inhabitants of seas
+now disjoined, and likewise of the past and present inhabitants of the
+temperate lands of North America and Europe, are inexplicable on the theory
+of creation.  We cannot say that they have been created alike, in
+correspondence with the nearly similar physical conditions of the areas;
+for if we compare, for instance, certain parts of South America with the
+southern continents of the Old World, we see countries closely
+corresponding in all their physical conditions, but with their inhabitants
+utterly dissimilar.
+</para>
+
+<para>
+But we must return to our more immediate subject, the Glacial period.  I am
+convinced that Forbes's view may be largely extended.  In Europe we have
+the plainest evidence of the cold period, from the western shores of
+Britain to the Oural range, and southward to the Pyrenees.  We may infer,
+from the frozen mammals and nature of the mountain vegetation, that Siberia
+was similarly affected.  Along the Himalaya, at points 900 miles apart,
+glaciers have left the marks of their former low descent; and in Sikkim,
+Dr. Hooker saw maize growing on gigantic ancient moraines.  South of the
+equator, we have some direct evidence of former glacial action in New
+Zealand; and the same plants, found on widely separated mountains in this
+island, tell the same story.  If one account which has been published can
+be trusted, we have direct evidence of glacial action in the south-eastern
+corner of Australia.
+</para>
+
+<para>
+Looking to America; in the northern half, ice-borne fragments of rock have
+been observed on the eastern side as far south as lat. 36 deg-37 deg, and
+on the shores of the Pacific, where the climate is now so different, as far
+south as lat. 46 deg; erratic boulders have, also, been noticed on the
+Rocky Mountains.  In the Cordillera of Equatorial South America, glaciers
+once extended far below their present level.  In central Chile I was
+astonished at the structure of a vast mound of detritus, about 800 feet in
+height, crossing a valley of the Andes; and this I now feel convinced was a
+gigantic moraine, left far below any existing glacier.  Further south on
+both sides of the continent, from lat. 41 deg to the southernmost
+extremity, we have the clearest evidence of former glacial action, in huge
+boulders transported far from their parent source.
+</para>
+
+<para>
+We do not know that the Glacial epoch was strictly simultaneous at these
+several far distant points on opposite sides of the world.  But we have
+good evidence in almost every case, that the epoch was included within the
+latest geological period.  We have, also, excellent evidence, that it
+endured for an enormous time, as measured by years, at each point.  The
+cold may have come on, or have ceased, earlier at one point of the globe
+than at another, but seeing that it endured for long at each, and that it
+was contemporaneous in a geological sense, it seems to me probable that it
+was, during a part at least of the period, actually simultaneous throughout
+the world.  Without some distinct evidence to the contrary, we may at least
+admit as probable that the glacial action was simultaneous on the eastern
+and western sides of North America, in the Cordillera under the equator and
+under the warmer temperate zones, and on both sides of the southern
+extremity of the continent.  If this be admitted, it is difficult to avoid
+believing that the temperature of the whole world was at this period
+simultaneously cooler.  But it would suffice for my purpose, if the
+temperature was at the same time lower along certain broad belts of
+longitude.
+</para>
+
+<para>
+On this view of the whole world, or at least of broad longitudinal belts,
+having been simultaneously colder from pole to pole, much light can be
+thrown on the present distribution of identical and allied species.  In
+America, Dr. Hooker has shown that between forty and fifty of the flowering
+plants of Tierra del Fuego, forming no inconsiderable part of its scanty
+flora, are common to Europe, enormously remote as these two points are; and
+there are many closely allied species.  On the lofty mountains of
+equatorial America a host of peculiar species belonging to European genera
+occur.  On the highest mountains of Brazil, some few European genera were
+found by Gardner, which do not exist in the wide intervening hot countries. 
+So on the Silla of Caraccas the illustrious Humboldt long ago found species
+belonging to genera characteristic of the Cordillera.  On the mountains of
+Abyssinia, several European forms and some few representatives of the
+peculiar flora of the Cape of Good Hope occur.  At the Cape of Good Hope a
+very few European species, believed not to have been introduced by man, and
+on the mountains, some few representative European forms are found, which
+have not been discovered in the intertropical parts of Africa.  On the
+Himalaya, and on the isolated mountain-ranges of the peninsula of India, on
+the heights of Ceylon, and on the volcanic cones of Java, many plants
+occur, either identically the same or representing each other, and at the
+same time representing plants of Europe, not found in the intervening hot
+lowlands.  A list of the genera collected on the loftier peaks of Java
+raises a picture of a collection made on a hill in Europe!  Still more
+striking is the fact that southern Australian forms are clearly represented
+by plants growing on the summits of the mountains of Borneo.  Some of these
+Australian forms, as I hear from Dr. Hooker, extend along the heights of
+the peninsula of Malacca, and are thinly scattered, on the one hand over
+India and on the other as far north as Japan.
+</para>
+
+<para>
+On the southern mountains of Australia, Dr. F. Muller has discovered
+several European species; other species, not introduced by man, occur on
+the lowlands; and a long list can be given, as I am informed by Dr. Hooker,
+of European genera, found in Australia, but not in the intermediate torrid
+regions.  In the admirable 'Introduction to the Flora of New Zealand,' by
+Dr. Hooker, analogous and striking facts are given in regard to the plants
+of that large island.  Hence we see that throughout the world, the plants
+growing on the more lofty mountains, and on the temperate lowlands of the
+northern and southern hemispheres, are sometimes identically the same; but
+they are much oftener specifically distinct, though related to each other
+in a most remarkable manner.
+</para>
+
+<para>
+This brief abstract applies to plants alone:  some strictly analogous facts
+could be given on the distribution of terrestrial animals.  In marine
+productions, similar cases occur; as an example, I may quote a remark by
+the highest authority, Prof. Dana, that 'it is certainly a wonderful fact
+that New Zealand should have a closer resemblance in its crustacea to Great
+Britain, its antipode, than to any other part of the world.'  Sir J.
+Richardson, also, speaks of the reappearance on the shores of New Zealand,
+Tasmania, &amp;c., of northern forms of fish.  Dr. Hooker informs me that
+twenty-five species of Algae are common to New Zealand and to Europe, but
+have not been found in the intermediate tropical seas.
+</para>
+
+<para>
+It should be observed that the northern species and forms found in the
+southern parts of the southern hemisphere, and on the mountain-ranges of
+the intertropical regions, are not arctic, but belong to the northern
+temperate zones.  As Mr. H. C. Watson has recently remarked, 'In receding
+from polar towards equatorial latitudes, the Alpine or mountain floras
+really become less and less arctic.'  Many of the forms living on the
+mountains of the warmer regions of the earth and in the southern hemisphere
+are of doubtful value, being ranked by some naturalists as specifically
+distinct, by others as varieties; but some are certainly identical, and
+many, though closely related to northern forms, must be ranked as distinct
+species.
+</para>
+
+<para>
+Now let us see what light can be thrown on the foregoing facts, on the
+belief, supported as it is by a large body of geological evidence, that the
+whole world, or a large part of it, was during the Glacial period
+simultaneously much colder than at present.  The Glacial period, as
+measured by years, must have been very long; and when we remember over what
+vast spaces some naturalised plants and animals have spread within a few
+centuries, this period will have been ample for any amount of migration. 
+As the cold came slowly on, all the tropical plants and other productions
+will have retreated from both sides towards the equator, followed in the
+rear by the temperate productions, and these by the arctic; but with the
+latter we are not now concerned.  The tropical plants probably suffered
+much extinction; how much no one can say; perhaps formerly the tropics
+supported as many species as we see at the present day crowded together at
+the Cape of Good Hope, and in parts of temperate Australia.  As we know
+that many tropical plants and animals can withstand a considerable amount
+of cold, many might have escaped extermination during a moderate fall of
+temperature, more especially by escaping into the warmest spots.  But the
+great fact to bear in mind is, that all tropical productions will have
+suffered to a certain extent.  On the other hand, the temperate
+productions, after migrating nearer to the equator, though they will have
+been placed under somewhat new conditions, will have suffered less.  And it
+is certain that many temperate plants, if protected from the inroads of
+competitors, can withstand a much warmer climate than their own.  Hence, it
+seems to me possible, bearing in mind that the tropical productions were in
+a suffering state and could not have presented a firm front against
+intruders, that a certain number of the more vigorous and dominant
+temperate forms might have penetrated the native ranks and have reached or
+even crossed the equator.  The invasion would, of course, have been greatly
+favoured by high land, and perhaps by a dry climate; for Dr. Falconer
+informs me that it is the damp with the heat of the tropics which is so
+destructive to perennial plants from a temperate climate.  On the other
+hand, the most humid and hottest districts will have afforded an asylum to
+the tropical natives.  The mountain-ranges north-west of the Himalaya, and
+the long line of the Cordillera, seem to have afforded two great lines of
+invasion:  and it is a striking fact, lately communicated to me by Dr.
+Hooker, that all the flowering plants, about forty-six in number, common to
+Tierra del Fuego and to Europe still exist in North America, which must
+have lain on the line of march.  But I do not doubt that some temperate
+productions entered and crossed even the lowlands of the  tropics at the
+period when the cold was most intense,--when arctic forms had migrated some
+twenty-five degrees of latitude from their native country and covered the
+land at the foot of the Pyrenees.  At this period of extreme cold, I
+believe that the climate under the equator at the level of the sea was
+about the same with that now felt there at the height of six or seven
+thousand feet.  During this the coldest period, I suppose that large spaces
+of the tropical lowlands were clothed with a mingled tropical and temperate
+vegetation, like that now growing with strange luxuriance at the base of
+the Himalaya, as graphically described by Hooker.
+</para>
+
+<para>
+Thus, as I believe, a considerable number of plants, a few terrestrial
+animals, and some marine productions, migrated during the Glacial period
+from the northern and southern temperate zones into the intertropical
+regions, and some even crossed the equator.  As the warmth returned, these
+temperate forms would naturally ascend the higher mountains, being
+exterminated on the lowlands; those which had not reached the equator,
+would re-migrate northward or southward towards their former homes; but the
+forms, chiefly northern, which had crossed the equator, would travel still
+further from their homes into the more temperate latitudes of the opposite
+hemisphere.  Although we have reason to believe from geological evidence
+that the whole body of arctic shells underwent scarcely any modification
+during their long southern migration and re-migration northward, the case
+may have been wholly different with those intruding forms which settled
+themselves on the intertropical mountains, and in the southern hemisphere. 
+These being surrounded by strangers will have had to compete with many new
+forms of life; and it is probable that selected modifications in their
+structure, habits, and constitutions will have profited them.  Thus many of
+these wanderers, though still plainly related by inheritance to their
+brethren of the northern or southern hemispheres, now exist in their new
+homes as well-marked varieties or as distinct species.
+</para>
+
+<para>
+It is a remarkable fact, strongly insisted on by Hooker in regard to
+America, and by Alph. de Candolle in regard to Australia, that many more
+identical plants and allied forms have apparently migrated from the north
+to the south, than in a reversed direction.  We see, however, a few
+southern vegetable forms on the mountains of Borneo and Abyssinia.  I
+suspect that this preponderant migration from north to south is due to the
+greater extent of land in the north, and to the northern forms having
+existed in their own homes in greater numbers, and having consequently been
+advanced through natural selection and competition to a higher stage of
+perfection or dominating power, than the southern forms.  And thus, when
+they became commingled during the Glacial period, the northern forms were
+enabled to beat the less powerful southern forms.  Just in the same manner
+as we see at the present day, that very many European productions cover the
+ground in La Plata, and in a lesser degree in Australia, and have to a
+certain extent beaten the natives; whereas extremely few southern forms
+have become naturalised in any part of Europe, though hides, wool, and
+other objects likely to carry seeds have been largely imported into Europe
+during the last two or three centuries from La Plata, and during the last
+thirty or forty years from Australia.  Something of the same kind must have
+occurred on the intertropical mountains:  no doubt before the Glacial
+period they were stocked with endemic Alpine forms; but these have almost
+everywhere largely yielded to the more dominant forms, generated in the
+larger areas and more efficient workshops of the north.  In many islands
+the native productions are nearly equalled or even outnumbered by the
+naturalised; and if the natives have not been actually exterminated, their
+numbers have been greatly reduced, and this is the first stage towards
+extinction.  A mountain is an island on the land; and the intertropical
+mountains before the Glacial period must have been completely isolated; and
+I believe that the productions of these islands on the land yielded to
+those produced within the larger areas of the north, just in the same way
+as the productions of real islands have everywhere lately yielded to
+continental forms, naturalised by man's agency.
+</para>
+
+<para>
+I am far from supposing that all difficulties are removed on the view here
+given in regard to the range and affinities of the allied species which
+live in the northern and southern temperate zones and on the mountains of
+the intertropical regions.  Very many difficulties remain to be solved.  I
+do not pretend to indicate the exact lines and means of migration, or the
+reason why certain species and not others have migrated; why certain
+species have been modified and have given rise to new groups of forms, and
+others have remained unaltered.  We cannot hope to explain such facts,
+until we can say why one species and not another becomes naturalised by
+man's agency in a foreign land; why one ranges twice or thrice as far, and
+is twice or thrice as common, as another species within their own homes.
+</para>
+
+<para>
+I have said that many difficulties remain to be solved:  some of the most
+remarkable are stated with admirable clearness by Dr. Hooker in his
+botanical works on the antarctic regions.  These cannot be here discussed. 
+I will only say that as far as regards the occurrence of identical species
+at points so enormously remote as Kerguelen Land, New Zealand, and Fuegia,
+I believe that towards the close of the Glacial period, icebergs, as
+suggested by Lyell, have been largely concerned in their dispersal.  But
+the existence of several quite distinct species, belonging to genera
+exclusively confined to the south, at these and other distant points of the
+southern hemisphere, is, on my theory of descent with modification, a far
+more remarkable case of difficulty.  For some of these species are so
+distinct, that we cannot suppose that there has been time since the
+commencement of the Glacial period for their migration, and for their
+subsequent modification to the necessary degree.  The facts seem to me to
+indicate that peculiar and very distinct species have migrated in radiating
+lines from some common centre; and I am inclined to look in the southern,
+as in the northern hemisphere, to a former and warmer period, before the
+commencement of the Glacial period, when the antarctic lands, now covered
+with ice, supported a highly peculiar and isolated flora.  I suspect that
+before this flora was exterminated by the Glacial epoch, a few forms were
+widely dispersed to various points of the southern hemisphere by occasional
+means of transport, and by the aid, as halting-places, of existing and now
+sunken islands, and perhaps at the commencement of the Glacial period, by
+icebergs.  By these means, as I believe, the southern shores of America,
+Australia, New Zealand have become slightly tinted by the same peculiar
+forms of vegetable life.
+</para>
+
+<para>
+Sir C. Lyell in a striking passage has speculated, in language almost
+identical with mine, on the effects of great alternations of climate on
+geographical distribution.  I believe that the world has recently felt one
+of his great cycles of change; and that on this view, combined with
+modification through natural selection, a multitude of facts in the present
+distribution both of the same and of allied forms of life can be explained. 
+The living waters may be said to have flowed during one short period from
+the north and from the south, and to have crossed at the equator; but to
+have flowed with greater force from the north so as to have freely
+inundated the south.  As the tide leaves its drift in horizontal lines,
+though rising higher on the shores where the tide rises highest, so have
+the living waters left their living drift on our mountain-summits, in a
+line gently rising from the arctic lowlands to a great height under the
+equator.  The various beings thus left stranded may be compared with savage
+races of man, driven up and surviving in the mountain-fastnesses of almost
+every land, which serve as a record, full of interest to us, of the former
+inhabitants of the surrounding lowlands.
+</para>
+
+</chapter>
+
+<chapter>
+<chapheader>
+
+<chapnum>Chapter XII</chapnum>
+
+<title>Geographical Distribution--continued</title>
+
+<chapsummary>
+Distribution of fresh-water productions -- On the inhabitants of oceanic
+islands -- Absence of Batrachians and of terrestrial Mammals -- On the
+relation of the inhabitants of islands to those of the nearest mainland --
+On colonisation from the nearest source with subsequent modification --
+Summary of the last and present chapters.
+</chapsummary>
+</chapheader>
+
+<para>
+As lakes and river-systems are separated from each other by barriers of
+land, it might have been thought that fresh-water productions would not
+have ranged widely within the same country, and as the sea is apparently a
+still more impassable barrier, that they never would have extended to
+distant countries.  But the case is exactly the reverse.  Not only have
+many fresh-water species, belonging to quite different classes, an enormous
+range, but allied species prevail in a remarkable manner throughout the
+world.  I well remember, when first collecting in the fresh waters of
+Brazil, feeling much surprise at the similarity of the fresh-water insects,
+shells, &amp;c., and at the dissimilarity of the surrounding terrestrial
+beings, compared with those of Britain.
+</para>
+
+<para>
+But this power in fresh-water productions of ranging widely, though so
+unexpected, can, I think, in most cases be explained by their having become
+fitted, in a manner highly useful to them, for short and frequent
+migrations from pond to pond, or from stream to stream; and liability to
+wide dispersal would follow from this capacity as an almost necessary
+consequence.  We can here consider only a few cases.  In regard to fish, I
+believe that the same species never occur in the fresh waters of distant
+continents.  But on the same continent the species often range widely and
+almost capriciously; for two river-systems will have some fish in common
+and some different.  A few facts seem to favour the possibility of their
+occasional transport by accidental means; like that of the live fish not
+rarely dropped by whirlwinds in India, and the vitality of their ova when
+removed from the water.  But I am inclined to attribute the dispersal of
+fresh-water fish mainly to slight changes within the recent period in the
+level of the land, having caused rivers to flow into each other. 
+Instances, also, could be given of this having occurred during floods,
+without any change of level.  We have evidence in the loess of the Rhine of
+considerable changes of level in the land within a very recent geological
+period, and when the surface was peopled by existing land and fresh-water
+shells.  The wide difference of the fish on opposite sides of continuous
+mountain-ranges, which from an early period must have parted river-systems
+and completely prevented their inosculation, seems to lead to this same
+conclusion.  With respect to allied fresh-water fish occurring at very
+distant points of the world, no doubt there are many cases which cannot at
+present be explained:  but some fresh-water fish belong to very ancient
+forms, and in such cases there will have been ample time for great
+geographical changes, and consequently time and means for much migration. 
+In the second place, salt-water fish can with care be slowly accustomed to
+live in fresh water; and, according to Valenciennes, there is hardly a
+single group of fishes confined exclusively to fresh water, so that we may
+imagine that a marine member of a fresh-water group might travel far along
+the shores of the sea, and subsequently become modified and adapted to the
+fresh waters of a distant land.
+</para>
+
+<para>
+Some species of fresh-water shells have a very wide range, and allied
+species, which, on my theory, are descended from a common parent and must
+have proceeded from a single source, prevail throughout the world.  Their
+distribution at first perplexed me much, as their ova are not likely to be
+transported by birds, and they are immediately killed by sea water, as are
+the adults.  I could not even understand how some naturalised species have
+rapidly spread throughout the same country.  But two facts, which I have
+observed--and no doubt many others remain to be observed--throw some light
+on this subject.  When a duck suddenly emerges from a pond covered with
+duck-weed, I have twice seen these little plants adhering to its back; and
+it has happened to me, in removing a little duck-weed from one aquarium to
+another, that I have quite unintentionally stocked the one with fresh-water
+shells from the other.  But another agency is perhaps more effectual:  I
+suspended a duck's feet, which might represent those of a bird sleeping in
+a natural pond, in an aquarium, where many ova of fresh-water shells were
+hatching; and I found that numbers of the extremely minute and just hatched
+shells crawled on the feet, and clung to them so firmly that when taken out
+of the water they could not be jarred off, though at a somewhat more
+advanced age they would voluntarily drop off.  These just hatched molluscs,
+though aquatic in their nature, survived on the duck's feet, in damp air,
+from twelve to twenty hours; and in this length of time a duck or heron
+might fly at least six or seven hundred miles, and would be sure to alight
+on a pool or rivulet, if blown across sea to an oceanic island or to any
+other distant point.  Sir Charles Lyell also informs me that a Dyticus has
+been caught with an Ancylus (a fresh-water shell like a limpet) firmly
+adhering to it; and a water-beetle of the same family, a Colymbetes, once
+flew on board the 'Beagle,' when forty-five miles distant from the nearest
+land:  how much farther it might have flown with a favouring gale no one
+can tell.
+</para>
+
+<para>
+With respect to plants, it has long been known what enormous ranges many
+fresh-water and even marsh-species have, both over continents and to the
+most remote oceanic islands.  This is strikingly shown, as remarked by
+Alph. de Candolle, in large groups of terrestrial plants, which have only a
+very few aquatic members; for these latter seem immediately to acquire, as
+if in consequence, a very wide range.  I think favourable means of
+dispersal explain this fact.  I have before mentioned that earth
+occasionally, though rarely, adheres in some quantity to the feet and beaks
+of birds.  Wading birds, which frequent the muddy edges of ponds, if
+suddenly flushed, would be the most likely to have muddy feet.  Birds of
+this order I can show are the greatest wanderers, and are occasionally
+found on the most remote and barren islands in the open ocean; they would
+not be likely to alight on the surface of the sea, so that the dirt would
+not be washed off their feet; when making land, they would be sure to fly
+to their natural fresh-water haunts.  I do not believe that botanists are
+aware how charged the mud of ponds is with seeds:  I have tried several
+little experiments, but will here give only the most striking case:  I took
+in February three table-spoonfuls of mud from three different points,
+beneath water, on the edge of a little pond; this mud when dry weighed only
+6 3/4 ounces; I kept it covered up in my study for six months, pulling up
+and counting each plant as it grew; the plants were of many kinds, and were
+altogether 537 in number; and yet the viscid mud was all contained in a
+breakfast cup!  Considering these facts, I think it would be an
+inexplicable circumstance if water-birds did not transport the seeds of
+fresh-water plants to vast distances, and if consequently the range of
+these plants was not very great.  The same agency may have come into play
+with the eggs of some of the smaller fresh-water animals.
+</para>
+
+<para>
+Other and unknown agencies probably have also played a part.  I have stated
+that fresh-water fish eat some kinds of seeds, though they reject many
+other kinds after having swallowed them; even small fish swallow seeds of
+moderate size, as of the yellow water-lily and Potamogeton.  Herons and
+other birds, century after century, have gone on daily devouring fish; they
+then take flight and go to other waters, or are blown across the sea; and
+we have seen that seeds retain their power of germination, when rejected in
+pellets or in excrement, many hours afterwards.  When I saw the great size
+of the seeds of that fine water-lily, the Nelumbium, and remembered Alph.
+de Candolle's remarks on this plant, I thought that its distribution must
+remain quite inexplicable; but Audubon states that he found the seeds of
+the great southern water-lily (probably, according to Dr. Hooker, the
+Nelumbium luteum) in a heron's stomach; although I do not know the fact,
+yet analogy makes me believe that a heron flying to another pond and
+getting a hearty meal of fish, would probably reject from its stomach a
+pellet containing the seeds of the Nelumbium undigested; or the seeds might
+be dropped by the bird whilst feeding its young, in the same way as fish
+are known sometimes to be dropped.
+</para>
+
+<para>
+In considering these several means of distribution, it should be remembered
+that when a pond or stream is first formed, for instance, on a rising
+islet, it will be unoccupied; and a single seed or egg will have a good
+chance of succeeding.  Although there will always be a struggle for life
+between the individuals of the species, however few, already occupying any
+pond, yet as the number of kinds is small, compared with those on the land,
+the competition will probably be less severe between aquatic than between
+terrestrial species; consequently an intruder from the waters of a foreign
+country, would have a better chance of seizing on a place, than in the case
+of terrestrial colonists.  We should, also, remember that some, perhaps
+many, fresh-water productions are low in the scale of nature, and that we
+have reason to believe that such low beings change or become modified less
+quickly than the high; and this will give longer time than the average for
+the migration of the same aquatic species.  We should not forget the
+probability of many species having formerly ranged as continuously as
+fresh-water productions ever can range, over immense areas, and having
+subsequently become extinct in intermediate regions.  But the wide
+distribution of fresh-water plants and of the lower animals, whether
+retaining the same identical form or in some degree modified, I believe
+mainly depends on the wide dispersal of their seeds and eggs by animals,
+more especially by fresh-water birds, which have large powers of flight,
+and naturally travel from one to another and often distant piece of water. 
+Nature, like a careful gardener, thus takes her seeds from a bed of a
+particular nature, and drops them in another equally well fitted for them.
+</para>
+
+<para>
+On the Inhabitants of Oceanic Islands. -- We now come to the last of the
+three classes of facts, which I have selected as presenting the greatest
+amount of difficulty, on the view that all the individuals both of the same
+and of allied species have descended from a single parent; and therefore
+have all proceeded from a common birthplace, notwithstanding that in the
+course of time they have come to inhabit distant points of the globe.  I
+have already stated that I cannot honestly admit Forbes's view on
+continental extensions, which, if legitimately followed out, would lead to
+the belief that within the recent period all existing islands have been
+nearly or quite joined to some continent.  This view would remove many
+difficulties, but it would not, I think, explain all the facts in regard to
+insular productions.  In the following remarks I shall not confine myself
+to the mere question of dispersal; but shall consider some other facts,
+which bear on the truth of the two theories of independent creation and of
+descent with modification.
+</para>
+
+<para>
+The species of all kinds which inhabit oceanic islands are few in number
+compared with those on equal continental areas:  Alph. de Candolle admits
+this for plants, and Wollaston for insects.  If we look to the large size
+and varied stations of New Zealand, extending over 780 miles of latitude,
+and compare its flowering plants, only 750 in number, with those on an
+equal area at the Cape of Good Hope or in Australia, we must, I think,
+admit that something quite independently of any difference in physical
+conditions has caused so great a difference in number.  Even the uniform
+county of Cambridge has 847 plants, and the little island of Anglesea 764,
+but a few ferns and a few introduced plants are included in these numbers,
+and the comparison in some other respects is not quite fair.  We have
+evidence that the barren island of Ascension aboriginally possessed under
+half-a-dozen flowering plants; yet many have become naturalised on it, as
+they have on New Zealand and on every other oceanic island which can be
+named.  In St. Helena there is reason to believe that the naturalised
+plants and animals have nearly or quite exterminated many native
+productions.  He who admits the doctrine of the creation of each separate
+species, will have to admit, that a sufficient number of the best adapted
+plants and animals have not been created on oceanic islands; for man has
+unintentionally stocked them from various sources far more fully and
+perfectly than has nature.
+</para>
+
+<para>
+Although in oceanic islands the number of kinds of inhabitants is scanty,
+the proportion of endemic species (i.e. those found nowhere else in the
+world) is often extremely large.  If we compare, for instance, the number
+of the endemic land-shells in Madeira, or of the endemic birds in the
+Galapagos Archipelago, with the number found on any continent, and then
+compare the area of the islands with that of the continent, we shall see
+that this is true.  This fact might have been expected on my theory, for,
+as already explained, species occasionally arriving after long intervals in
+a new and isolated district, and having to compete with new associates,
+will be eminently liable to modification, and will often produce groups of
+modified descendants.  But it by no means follows, that, because in an
+island nearly all the species of one class are peculiar, those of another
+class, or of another section of the same class, are peculiar; and this
+difference seems to depend on the species which do not become modified
+having immigrated with facility and in a body, so that their mutual
+relations have not been much disturbed.  Thus in the Galapagos Islands
+nearly every land-bird, but only two out of the eleven marine birds, are
+peculiar; and it is obvious that marine birds could arrive at these islands
+more easily than land-birds.  Bermuda, on the other hand, which lies at
+about the same distance from North America as the Galapagos Islands do from
+South America, and which has a very peculiar soil, does not possess one
+endemic land bird; and we know from Mr. J. M. Jones's admirable account of
+Bermuda, that very many North American birds, during their great annual
+migrations, visit either periodically or occasionally this island.  Madeira
+does not possess one peculiar bird, and many European and African birds are
+almost every year blown there, as I am informed by Mr. E. V. Harcourt.  So
+that these two islands of Bermuda and Madeira have been stocked by birds,
+which for long ages have struggled together in their former homes, and have
+become mutually adapted to each other; and when settled in their new homes,
+each kind will have been kept by the others to their proper places and
+habits, and will consequently have been little liable to modification. 
+Madeira, again, is inhabited by a wonderful number of peculiar land-shells,
+whereas not one species of sea-shell is confined to its shores:  now,
+though we do not know how seashells are dispersed, yet we can see that
+their eggs or larvae, perhaps attached to seaweed or floating timber, or to
+the feet of wading-birds, might be transported far more easily than
+land-shells, across three or four hundred miles of open sea.  The different
+orders of insects in Madeira apparently present analogous facts.
+</para>
+
+<para>
+Oceanic islands are sometimes deficient in certain classes, and their
+places are apparently occupied by the other inhabitants; in the Galapagos
+Islands reptiles, and in New Zealand gigantic wingless birds, take the
+place of mammals.  In the plants of the Galapagos Islands, Dr. Hooker has
+shown that the proportional numbers of the different orders are very
+different from what they are elsewhere.  Such cases are generally accounted
+for by the physical conditions of the islands; but this explanation seems
+to me not a little doubtful.  Facility of immigration, I believe, has been
+at least as important as the nature of the conditions.
+</para>
+
+<para>
+Many remarkable little facts could be given with respect to the inhabitants
+of remote islands.  For instance, in certain islands not tenanted by
+mammals, some of the endemic plants have beautifully hooked seeds; yet few
+relations are more striking than the adaptation of hooked seeds for
+transportal by the wool and fur of quadrupeds.  This case presents no
+difficulty on my view, for a hooked seed might be transported to an island
+by some other means; and the plant then becoming slightly modified, but
+still retaining its hooked seeds, would form an endemic species, having as
+useless an appendage as any rudimentary organ,--for instance, as the
+shrivelled wings under the soldered elytra of many insular beetles.  Again,
+islands often possess trees or bushes belonging to orders which elsewhere
+include only herbaceous species; now trees, as Alph. de Candolle has shown,
+generally have, whatever the cause may be, confined ranges.  Hence trees
+would be little likely to reach distant oceanic islands; and an herbaceous
+plant, though it would have no chance of successfully competing in stature
+with a fully developed tree, when established on an island and having to
+compete with herbaceous plants alone, might readily gain an advantage by
+growing taller and taller and overtopping the other plants.  If so, natural
+selection would often tend to add to the stature of herbaceous plants when
+growing on an island, to whatever order they belonged, and thus convert
+them first into bushes and ultimately into trees.
+</para>
+
+<para>
+With respect to the absence of whole orders on oceanic islands, Bory St.
+Vincent long ago remarked that Batrachians (frogs, toads, newts) have never
+been found on any of the many islands with which the great oceans are
+studded.  I have taken pains to verify this assertion, and I have found it
+strictly true.  I have, however, been assured that a frog exists on the
+mountains of the great island of New Zealand; but I suspect that this
+exception (if the information be correct) may be explained through glacial
+agency.  This general absence of frogs, toads, and newts on so many oceanic
+islands cannot be accounted for by their physical conditions; indeed it
+seems that islands are peculiarly well fitted for these animals; for frogs
+have been introduced into Madeira, the Azores, and Mauritius, and have
+multiplied so as to become a nuisance.  But as these animals and their
+spawn are known to be immediately killed by sea-water, on my view we can
+see that there would be great difficulty in their transportal across the
+sea, and therefore why they do not exist on any oceanic island.  But why,
+on the theory of creation, they should not have been created there, it
+would be very difficult to explain.
+</para>
+
+<para>
+Mammals offer another and similar case.  I have carefully searched the
+oldest voyages, but have not finished my search; as yet I have not found a
+single instance, free from doubt, of a terrestrial mammal (excluding
+domesticated animals kept by the natives) inhabiting an island situated
+above 300 miles from a continent or great continental island; and many
+islands situated at a much less distance are equally barren.  The Falkland
+Islands, which are inhabited by a wolf-like fox, come nearest to an
+exception; but this group cannot be considered as oceanic, as it lies on a
+bank connected with the mainland; moreover, icebergs formerly brought
+boulders to its western shores, and they may have formerly transported
+foxes, as so frequently now happens in the arctic regions.  Yet it cannot
+be said that small islands will not support small mammals, for they occur
+in many parts of the world on very small islands, if close to a continent;
+and hardly an island can be named on which our smaller quadrupeds have not
+become naturalised and greatly multiplied.  It cannot be said, on the
+ordinary view of creation, that there has not been time for the creation of
+mammals; many volcanic islands are sufficiently ancient, as shown by the
+stupendous degradation which they have suffered and by their tertiary
+strata:  there has also been time for the production of endemic species
+belonging to other classes; and on continents it is thought that mammals
+appear and disappear at a quicker rate than other and lower animals. 
+Though terrestrial mammals do not occur on oceanic islands, aerial mammals
+do occur on almost every island.  New Zealand possesses two bats found
+nowhere else in the world:  Norfolk Island, the Viti Archipelago, the Bonin
+Islands, the Caroline and Marianne Archipelagoes, and Mauritius, all
+possess their peculiar bats.  Why, it may be asked, has the supposed
+creative force produced bats and no other mammals on remote islands?  On my
+view this question can easily be answered; for no terrestrial mammal can be
+transported across a wide space of sea, but bats can fly across.  Bats have
+been seen wandering by day far over the Atlantic Ocean; and two North
+American species either regularly or occasionally visit Bermuda, at the
+distance of 600 miles from the mainland.  I hear from Mr. Tomes, who has
+specially studied this family, that many of the same species have enormous
+ranges, and are found on continents and on far distant islands.  Hence we
+have only to suppose that such wandering species have been modified through
+natural selection in their new homes in relation to their new position, and
+we can understand the presence of endemic bats on islands, with the absence
+of all terrestrial mammals.
+</para>
+
+<para>
+Besides the absence of terrestrial mammals in relation to the remoteness of
+islands from continents, there is also a relation, to a certain extent
+independent of distance, between the depth of the sea separating an island
+from the neighbouring mainland, and the presence in both of the same
+mammiferous species or of allied species in a more or less modified
+condition.  Mr. Windsor Earl has made some striking observations on this
+head in regard to the great Malay Archipelago, which is traversed near
+Celebes by a space of deep ocean; and this space separates two widely
+distinct mammalian faunas.  On either side the islands are situated on
+moderately deep submarine banks, and they are inhabited by closely allied
+or identical quadrupeds.  No doubt some few anomalies occur in this great
+archipelago, and there is much difficulty in forming a judgment in some
+cases owing to the probable naturalisation of certain mammals through man's
+agency; but we shall soon have much light thrown on the natural history of
+this archipelago by the admirable zeal and researches of Mr. Wallace.  I
+have not as yet had time to follow up this subject in all other quarters of
+the world; but as far as I have gone, the relation generally holds good. 
+We see Britain separated by a shallow channel from Europe, and the mammals
+are the same on both sides; we meet with analogous facts on many islands
+separated by similar channels from Australia.  The West Indian Islands
+stand on a deeply submerged bank, nearly 1000 fathoms in depth, and here we
+find American forms, but the species and even the genera are distinct.  As
+the amount of modification in all cases depends to a certain degree on the
+lapse of time, and as during changes of level it is obvious that islands
+separated by shallow channels are more likely to have been continuously
+united within a recent period to the mainland than islands separated by
+deeper channels, we can understand the frequent relation between the depth
+of the sea and the degree of affinity of the mammalian inhabitants of
+islands with those of a neighbouring continent,--an inexplicable relation
+on the view of independent acts of creation.
+</para>
+
+<para>
+All the foregoing remarks on the inhabitants of oceanic islands,--namely,
+the scarcity of kinds--the richness in endemic forms in particular classes
+or sections of classes,--the absence of whole groups, as of batrachians,
+and of terrestrial mammals notwithstanding the presence of aerial
+bats,--the singular proportions of certain orders of plants,--herbaceous
+forms having been developed into trees, &amp;c.,--seem to me to accord better
+with the view of occasional means of transport having been largely
+efficient in the long course of time, than with the view of all our oceanic
+islands having been formerly connected by continuous land with the nearest
+continent; for on this latter view the migration would probably have been
+more complete; and if modification be admitted, all the forms of life would
+have been more equally modified, in accordance with the paramount
+importance of the relation of organism to organism.
+</para>
+
+<para>
+I do not deny that there are many and grave difficulties in understanding
+how several of the inhabitants of the more remote islands, whether still
+retaining the same specific form or modified since their arrival, could
+have reached their present homes.  But the probability of many islands
+having existed as halting-places, of which not a wreck now remains, must
+not be overlooked.  I will here give a single instance of one of the cases
+of difficulty.  Almost all oceanic islands, even the most isolated and
+smallest, are inhabited by land-shells, generally by endemic species, but
+sometimes by species found elsewhere.  Dr. Aug. A. Gould has given several
+interesting cases in regard to the land-shells of the islands of the
+Pacific.  Now it is notorious that land-shells are very easily killed by
+salt; their eggs, at least such as I have tried, sink in sea-water and are
+killed by it.  Yet there must be, on my view, some unknown, but highly
+efficient means for their transportal.  Would the just-hatched young
+occasionally crawl on and adhere to the feet of birds roosting on the
+ground, and thus get transported?  It occurred to me that land-shells, when
+hybernating and having a membranous diaphragm over the mouth of the shell,
+might be floated in chinks of drifted timber across moderately wide arms of
+the sea.  And I found that several species did in this state withstand
+uninjured an immersion in sea-water during seven days:  one of these shells
+was the Helix pomatia, and after it had again hybernated I put it in
+sea-water for twenty days, and it perfectly recovered.  As this species has
+a thick calcareous operculum, I removed it, and when it had formed a new
+membranous one, I immersed it for fourteen days in sea-water, and it
+recovered and crawled away:  but more experiments are wanted on this head.
+</para>
+
+<para>
+The most striking and important fact for us in regard to the inhabitants of
+islands, is their affinity to those of the nearest mainland, without being
+actually the same species.  Numerous instances could be given of this fact. 
+I will give only one, that of the Galapagos Archipelago, situated under the
+equator, between 500 and 600 miles from the shores of South America.  Here
+almost every product of the land and water bears the unmistakeable stamp of
+the American continent.  There are twenty-six land birds, and twenty-five
+of these are ranked by Mr. Gould as distinct species, supposed to have been
+created here; yet the close affinity of most of these birds to American
+species in every character, in their habits, gestures, and tones of voice,
+was manifest.  So it is with the other animals, and with nearly all the
+plants, as shown by Dr. Hooker in his admirable memoir on the Flora of this
+archipelago.  The naturalist, looking at the inhabitants of these volcanic
+islands in the Pacific, distant several hundred miles from the continent,
+yet feels that he is standing on American land.  Why should this be so? why
+should the species which are supposed to have been created in the Galapagos
+Archipelago, and nowhere else, bear so plain a stamp of affinity to those
+created in America?  There is nothing in the conditions of life, in the
+geological nature of the islands, in their height or climate, or in the
+proportions in which the several classes are associated together, which
+resembles closely the conditions of the South American coast:  in fact
+there is a considerable dissimilarity in all these respects.  On the other
+hand, there is a considerable degree of resemblance in the volcanic nature
+of the soil, in climate, height, and size of the islands, between the
+Galapagos and Cape de Verde Archipelagos:  but what an entire and absolute
+difference in their inhabitants!  The inhabitants of the Cape de Verde
+Islands are related to those of Africa, like those of the Galapagos to
+America.  I believe this grand fact can receive no sort of explanation on
+the ordinary view of independent creation; whereas on the view here
+maintained, it is obvious that the Galapagos Islands would be likely to
+receive colonists, whether by occasional means of transport or by formerly
+continuous land, from America; and the Cape de Verde Islands from Africa;
+and that such colonists would be liable to modification;--the principle of
+inheritance still betraying their original birthplace.
+</para>
+
+<para>
+Many analogous facts could be given:  indeed it is an almost universal rule
+that the endemic productions of islands are related to those of the nearest
+continent, or of other near islands.  The exceptions are few, and most of
+them can be explained.  Thus the plants of Kerguelen Land, though standing
+nearer to Africa than to America, are related, and that very closely, as we
+know from Dr. Hooker's account, to those of America:  but on the view that
+this island has been mainly stocked by seeds brought with earth and stones
+on icebergs, drifted by the prevailing currents, this anomaly disappears. 
+New Zealand in its endemic plants is much more closely related to
+Australia, the nearest mainland, than to any other region:  and this is
+what might have been expected; but it is also plainly related to South
+America, which, although the next nearest continent, is so enormously
+remote, that the fact becomes an anomaly.  But this difficulty almost
+disappears on the view that both New Zealand, South America, and other
+southern lands were long ago partially stocked from a nearly intermediate
+though distant point, namely from the antarctic islands, when they were
+clothed with vegetation, before the commencement of the Glacial period. 
+The affinity, which, though feeble, I am assured by Dr. Hooker is real,
+between the flora of the south-western corner of Australia and of the Cape
+of Good Hope, is a far more remarkable case, and is at present
+inexplicable:  but this affinity is confined to the plants, and will, I do
+not doubt, be some day explained.
+</para>
+
+<para>
+The law which causes the inhabitants of an archipelago, though specifically
+distinct, to be closely allied to those of the nearest continent, we
+sometimes see displayed on a small scale, yet in a most interesting manner,
+within the limits of the same archipelago.  Thus the several islands of the
+Galapagos Archipelago are tenanted, as I have elsewhere shown, in a quite
+marvellous manner, by very closely related species; so that the inhabitants
+of each separate island, though mostly distinct, are related in an
+incomparably closer degree to each other than to the inhabitants of any
+other part of the world.  And this is just what might have been expected on
+my view, for the islands are situated so near each other that they would
+almost certainly receive immigrants from the same original source, or from
+each other.  But this dissimilarity between the endemic inhabitants of the
+islands may be used as an argument against my views; for it may be asked,
+how has it happened in the several islands situated within sight of each
+other, having the same geological nature, the same height, climate, &amp;c.,
+that many of the immigrants should have been differently modified, though
+only in a small degree.  This long appeared to me a great difficulty:  but
+it arises in chief part from the deeply-seated error of considering the
+physical conditions of a country as the most important for its inhabitants;
+whereas it cannot, I think, be disputed that the nature of the other
+inhabitants, with which each has to compete, is at least as important, and
+generally a far more important element of success.  Now if we look to those
+inhabitants of the Galapagos Archipelago which are found in other parts of
+the world (laying on one side for the moment the endemic species, which
+cannot be here fairly included, as we are considering how they have come to
+be modified since their arrival), we find a considerable amount of
+difference in the several islands.  This difference might indeed have been
+expected on the view of the islands having been stocked by occasional means
+of transport--a seed, for instance, of one plant having been brought to one
+island, and that of another plant to another island.  Hence when in former
+times an immigrant settled on any one or more of the islands, or when it
+subsequently spread from one island to another, it would undoubtedly be
+exposed to different conditions of life in the different islands, for it
+would have to compete with different sets of organisms:  a plant, for
+instance, would find the best-fitted ground more perfectly occupied by
+distinct plants in one island than in another, and it would be exposed to
+the attacks of somewhat different enemies.  If then it varied, natural
+selection would probably favour different varieties in the different
+islands.  Some species, however, might spread and yet retain the same
+character throughout the group, just as we see on continents some species
+spreading widely and remaining the same.
+</para>
+
+<para>
+The really surprising fact in this case of the Galapagos Archipelago, and
+in a lesser degree in some analogous instances, is that the new species
+formed in the separate islands have not quickly spread to the other
+islands.  But the islands, though in sight of each other, are separated by
+deep arms of the sea, in most cases wider than the British Channel, and
+there is no reason to suppose that they have at any former period been
+continuously united.  The currents of the sea are rapid and sweep across
+the archipelago, and gales of wind are extraordinarily rare; so that the
+islands are far more effectually separated from each other than they appear
+to be on a map.  Nevertheless a good many species, both those found in
+other parts of the world and those confined to the archipelago, are common
+to the several islands, and we may infer from certain facts that these have
+probably spread from some one island to the others.  But we often take, I
+think, an erroneous view of the probability of closely allied species
+invading each other's territory, when put into free intercommunication. 
+Undoubtedly if one species has any advantage whatever over another, it will
+in a very brief time wholly or in part supplant it; but if both are equally
+well fitted for their own places in nature, both probably will hold their
+own places and keep separate for almost any length of time.  Being familiar
+with the fact that many species, naturalised through man's agency, have
+spread with astonishing rapidity over new countries, we are apt to infer
+that most species would thus spread; but we should remember that the forms
+which become naturalised in new countries are not generally closely allied
+to the aboriginal inhabitants, but are very distinct species, belonging in
+a large proportion of cases, as shown by Alph. de Candolle, to distinct
+genera.  In the Galapagos Archipelago, many even of the birds, though so
+well adapted for flying from island to island, are distinct on each; thus
+there are three closely-allied species of mocking-thrush, each confined to
+its own island.  Now let us suppose the mocking-thrush of Chatham Island to
+be blown to Charles Island, which has its own mocking-thrush:  why should
+it succeed in establishing itself there?  We may safely infer that Charles
+Island is well stocked with its own species, for annually more eggs are
+laid there than can possibly be reared; and we may infer that the
+mocking-thrush peculiar to Charles Island is at least as well fitted for
+its home as is the species peculiar to Chatham Island.  Sir C. Lyell and
+Mr. Wollaston have communicated to me a remarkable fact bearing on this
+subject; namely, that Madeira and the adjoining islet of Porto Santo
+possess many distinct but representative land-shells, some of which live in
+crevices of stone; and although large quantities of stone are annually
+transported from Porto Santo to Madeira, yet this latter island has not
+become colonised by the Porto Santo species:  nevertheless both islands
+have been colonised by some European land-shells, which no doubt had some
+advantage over the indigenous species.  From these considerations I think
+we need not greatly marvel at the endemic and representative species, which
+inhabit the several islands of the Galapagos Archipelago, not having
+universally spread from island to island.  In many other instances, as in
+the several districts of the same continent, pre-occupation has probably
+played an important part in checking the commingling of species under the
+same conditions of life.  Thus, the south-east and south-west corners of
+Australia have nearly the same physical conditions, and are united by
+continuous land, yet they are inhabited by a vast number of distinct
+mammals, birds, and plants.
+</para>
+
+<para>
+The principle which determines the general character of the fauna and flora
+of oceanic islands, namely, that the inhabitants, when not identically the
+same, yet are plainly related to the inhabitants of that region whence
+colonists could most readily have been derived,--the colonists having been
+subsequently modified and better fitted to their new homes,--is of the
+widest application throughout nature.  We see this on every mountain, in
+every lake and marsh.  For Alpine species, excepting in so far as the same
+forms, chiefly of plants, have spread widely throughout the world during
+the recent Glacial epoch, are related to those of the surrounding
+lowlands;--thus we have in South America, Alpine humming-birds, Alpine
+rodents, Alpine plants, &amp;c., all of strictly American forms, and it is
+obvious that a mountain, as it became slowly upheaved, would naturally be
+colonised from the surrounding lowlands.  So it is with the inhabitants of
+lakes and marshes, excepting in so far as great facility of transport has
+given the same general forms to the whole world.  We see this same
+principle in the blind animals inhabiting the caves of America and of
+Europe.  Other analogous facts could be given.  And it will, I believe, be
+universally found to be true, that wherever in two regions, let them be
+ever so distant, many closely allied or representative species occur, there
+will likewise be found some identical species, showing, in accordance with
+the foregoing view, that at some former period there has been
+intercommunication or migration between the two regions.  And wherever many
+closely-allied species occur, there will be found many forms which some
+naturalists rank as distinct species, and some as varieties; these doubtful
+forms showing us the steps in the process of modification.
+</para>
+
+<para>
+This relation between the power and extent of migration of a species,
+either at the present time or at some former period under different
+physical conditions, and the existence at remote points of the world of
+other species allied to it, is shown in another and more general way.  Mr.
+Gould remarked to me long ago, that in those genera of birds which range
+over the world, many of the species have very wide ranges.  I can hardly
+doubt that this rule is generally true, though it would be difficult to
+prove it.  Amongst mammals, we see it strikingly displayed in Bats, and in
+a lesser degree in the Felidae and Canidae.  We see it, if we compare the
+distribution of butterflies and beetles.  So it is with most fresh-water
+productions, in which so many genera range over the world, and many
+individual species have enormous ranges.  It is not meant that in
+world-ranging genera all the species have a wide range, or even that they
+have on an average a wide range; but only that some of the species range
+very widely; for the facility with which widely-ranging species vary and
+give rise to new forms will largely determine their average range.  For
+instance, two varieties of the same species inhabit America and Europe, and
+the species thus has an immense range; but, if the variation had been a
+little greater, the two varieties would have been ranked as distinct
+species, and the common range would have been greatly reduced.  Still less
+is it meant, that a species which apparently has the capacity of crossing
+barriers and ranging widely, as in the case of certain powerfully-winged
+birds, will necessarily range widely; for we should never forget that to
+range widely implies not only the power of crossing barriers, but the more
+important power of being victorious in distant lands in the struggle for
+life with foreign associates.  But on the view of all the species of a
+genus having descended from a single parent, though now distributed to the
+most remote points of the world, we ought to find, and I believe as a
+general rule we do find, that some at least of the species range very
+widely; for it is necessary that the unmodified parent should range widely,
+undergoing modification during its diffusion, and should place itself under
+diverse conditions favourable for the conversion of its offspring, firstly
+into new varieties and ultimately into new species.
+</para>
+
+<para>
+In considering the wide distribution of certain genera, we should bear in
+mind that some are extremely ancient, and must have branched off from a
+common parent at a remote epoch; so that in such cases there will have been
+ample time for great climatal and geographical changes and for accidents of
+transport; and consequently for the migration of some of the species into
+all quarters of the world, where they may have become slightly modified in
+relation to their new conditions.  There is, also, some reason to believe
+from geological evidence that organisms low in the scale within each great
+class, generally change at a slower rate than the higher forms; and
+consequently the lower forms will have had a better chance of ranging
+widely and of still retaining the same specific character.  This fact,
+together with the seeds and eggs of many low forms being very minute and
+better fitted for distant transportation, probably accounts for a law which
+has long been observed, and which has lately been admirably discussed by
+Alph. de Candolle in regard to plants, namely, that the lower any group of
+organisms is, the more widely it is apt to range.
+</para>
+
+<para>
+The relations just discussed,--namely, low and slowly-changing organisms
+ranging more widely than the high,--some of the species of widely-ranging
+genera themselves ranging widely,--such facts, as alpine, lacustrine, and
+marsh productions being related (with the exceptions before specified) to
+those on the surrounding low lands and dry lands, though these stations are
+so different--the very close relation of the distinct species which inhabit
+the islets of the same archipelago,--and especially the striking relation
+of the inhabitants of each whole archipelago or island to those of the
+nearest mainland,--are, I think, utterly inexplicable on the ordinary view
+of the independent creation of each species, but are explicable on the view
+of colonisation from the nearest and readiest source, together with the
+subsequent modification and better adaptation of the colonists to their new
+homes.
+</para>
+
+<para>
+Summary of last and present Chapters -- In these chapters I have
+endeavoured to show, that if we make due allowance for our ignorance of the
+full effects of all the changes of climate and of the level of the land,
+which have certainly occurred within the recent period, and of other
+similar changes which may have occurred within the same period; if we
+remember how profoundly ignorant we are with respect to the many and
+curious means of occasional transport,--a subject which has hardly ever
+been properly experimentised on; if we bear in mind how often a species may
+have ranged continuously over a wide area, and then have become extinct in
+the intermediate tracts, I think the difficulties in believing that all the
+individuals of the same species, wherever located, have descended from the
+same parents, are not insuperable.  And we are led to this conclusion,
+which has been arrived at by many naturalists under the designation of
+single centres of creation, by some general considerations, more especially
+from the importance of barriers and from the analogical distribution of
+sub-genera, genera, and families.
+</para>
+
+<para>
+With respect to the distinct species of the same genus, which on my theory
+must have spread from one parent-source; if we make the same allowances as
+before for our ignorance, and remember that some forms of life change most
+slowly, enormous periods of time being thus granted for their migration, I
+do not think that the difficulties are insuperable; though they often are
+in this case, and in that of the individuals of the same species, extremely
+grave.
+</para>
+
+<para>
+As exemplifying the effects of climatal changes on distribution, I have
+attempted to show how important has been the influence of the modern
+Glacial period, which I am fully convinced simultaneously affected the
+whole world, or at least great meridional belts.  As showing how
+diversified are the means of occasional transport, I have discussed at some
+little length the means of dispersal of fresh-water productions.
+</para>
+
+<para>
+If the difficulties be not insuperable in admitting that in the long course
+of time the individuals of the same species, and likewise of allied
+species, have proceeded from some one source; then I think all the grand
+leading facts of geographical distribution are explicable on the theory of
+migration (generally of the more dominant forms of life), together with
+subsequent modification and the multiplication of new forms.  We can thus
+understand the high importance of barriers, whether of land or water, which
+separate our several zoological and botanical provinces.  We can thus
+understand the localisation of sub-genera, genera, and families; and how it
+is that under different latitudes, for instance in South America, the
+inhabitants of the plains and mountains, of the forests, marshes, and
+deserts, are in so mysterious a manner linked together by affinity, and are
+likewise linked to the extinct beings which formerly inhabited the same
+continent.  Bearing in mind that the mutual relations of organism to
+organism are of the highest importance, we can see why two areas having
+nearly the same physical conditions should often be inhabited by very
+different forms of life; for according to the length of time which has
+elapsed since new inhabitants entered one region; according to the nature
+of the communication which allowed certain forms and not others to enter,
+either in greater or lesser numbers; according or not, as those which
+entered happened to come in more or less direct competition with each other
+and with the aborigines; and according as the immigrants were capable of
+varying more or less rapidly, there would ensue in different regions,
+independently of their physical conditions, infinitely diversified
+conditions of life,--there would be an almost endless amount of organic
+action and reaction,--and we should find, as we do find, some groups of
+beings greatly, and some only slightly modified,--some developed in great
+force, some existing in scanty numbers--in the different great geographical
+provinces of the world.
+</para>
+
+<para>
+On these same principles, we can understand, as I have endeavoured to show,
+why oceanic islands should have few inhabitants, but of these a great
+number should be endemic or peculiar; and why, in relation to the means of
+migration, one group of beings, even within the same class, should have all
+its species endemic, and another group should have all its species common
+to other quarters of the world.  We can see why whole groups of organisms,
+as batrachians and terrestrial mammals, should be absent from oceanic
+islands, whilst the most isolated islands possess their own peculiar
+species of aerial mammals or bats.  We can see why there should be some
+relation between the presence of mammals, in a more or less modified
+condition, and the depth of the sea between an island and the mainland.  We
+can clearly see why all the inhabitants of an archipelago, though
+specifically distinct on the several islets, should be closely related to
+each other, and likewise be related, but less closely, to those of the
+nearest continent or other source whence immigrants were probably derived. 
+We can see why in two areas, however distant from each other, there should
+be a correlation, in the presence of identical species, of varieties, of
+doubtful species, and of distinct but representative species.
+</para>
+
+<para>
+As the late Edward Forbes often insisted, there is a striking parallelism
+in the laws of life throughout time and space:  the laws governing the
+succession of forms in past times being nearly the same with those
+governing at the present time the differences in different areas.  We see
+this in many facts.  The endurance of each species and group of species is
+continuous in time; for the exceptions to the rule are so few, that they
+may fairly be attributed to our not having as yet discovered in an
+intermediate deposit the forms which are therein absent, but which occur
+above and below:  so in space, it certainly is the general rule that the
+area inhabited by a single species, or by a group of species, is
+continuous; and the exceptions, which are not rare, may, as I have
+attempted to show, be accounted for by migration at some former period
+under different conditions or by occasional means of transport, and by the
+species having become extinct in the intermediate tracts.  Both in time and
+space, species and groups of species have their points of maximum
+development.  Groups of species, belonging either to a certain period of
+time, or to a certain area, are often characterised by trifling characters
+in common, as of sculpture or colour.  In looking to the long succession of
+ages, as in now looking to distant provinces throughout the world, we find
+that some organisms differ little, whilst others belonging to a different
+class, or to a different order, or even only to a different family of the
+same order, differ greatly.  In both time and space the lower members of
+each class generally change less than the higher; but there are in both
+cases marked exceptions to the rule.  On my theory these several relations
+throughout time and space are intelligible; for whether we look to the
+forms of life which have changed during successive ages within the same
+quarter of the world, or to those which have changed after having migrated
+into distant quarters, in both cases the forms within each class have been
+connected by the same bond of ordinary generation; and the more nearly any
+two forms are related in blood, the nearer they will generally stand to
+each other in time and space; in both cases the laws of variation have been
+the same, and modifications have been accumulated by the same power of
+natural selection.
+</para>
+
+</chapter>
+
+<chapter>
+<chapheader>
+
+
+<chapnum>Chapter XIII</chapnum>
+
+<title>Mutual Affinities of Organic Beings:
+Morphology:  Embryology:  Rudimentary Organs</title>
+
+<chapsummary>
+Classification, groups subordinate to groups -- Natural system -- Rules and
+difficulties in classification, explained on the theory of descent with
+modification -- Classification of varieties -- Descent always used in
+classification -- Analogical or adaptive characters -- Affinities, general,
+complex and radiating -- Extinction separates and defines groups --
+Morphology, between members of the same class, between parts of the same
+individual -- Embryology, laws of, explained by variations not supervening
+at an early age, and being inherited at a corresponding age -- Rudimentary
+Organs; their origin explained -- Summary.
+</chapsummary>
+</chapheader>
+
+<para>
+From the first dawn of life, all organic beings are found to resemble each
+other in descending degrees, so that they can be classed in groups under
+groups.  This classification is evidently not arbitrary like the grouping
+of the stars in constellations.  The existence of groups would have been of
+simple signification, if one group had been exclusively fitted to inhabit
+the land, and another the water; one to feed on flesh, another on vegetable
+matter, and so on; but the case is widely different in nature; for it is
+notorious how commonly members of even the same subgroup have different
+habits.  In our second and fourth chapters, on Variation and on Natural
+Selection, I have attempted to show that it is the widely ranging, the much
+diffused and common, that is the dominant species belonging to the larger
+genera, which vary most.  The varieties, or incipient species, thus
+produced ultimately become converted, as I believe, into new and distinct
+species; and these, on the principle of inheritance, tend to produce other
+new and dominant species.  Consequently the groups which are now large, and
+which generally include many dominant species, tend to go on increasing
+indefinitely in size.  I further attempted to show that from the varying
+descendants of each species trying to occupy as many and as different
+places as possible in the economy of nature, there is a constant tendency
+in their characters to diverge.  This conclusion was supported by looking
+at the great diversity of the forms of life which, in any small area, come
+into the closest competition, and by looking to certain facts in
+naturalisation.
+</para>
+
+<para>
+I attempted also to show that there is a constant tendency in the forms
+which are increasing in number and diverging in character, to supplant and
+exterminate the less divergent, the less improved, and preceding forms.  I
+request the reader to turn to the diagram illustrating the action, as
+formerly explained, of these several principles; and he will see that the
+inevitable result is that the modified descendants proceeding from one
+progenitor become broken up into groups subordinate to groups.  In the
+diagram each letter on the uppermost line may represent a genus including
+several species; and all the genera on this line form together one class,
+for all have descended from one ancient but unseen parent, and,
+consequently, have inherited something in common.  But the three genera on
+the left hand have, on this same principle, much in common, and form a
+sub-family, distinct from that including the next two genera on the right
+hand, which diverged from a common parent at the fifth stage of descent. 
+These five genera have also much, though less, in common; and they form a
+family distinct from that including the three genera still further to the
+right hand, which diverged at a still earlier period.  And all these
+genera, descended from (A), form an order distinct from the genera
+descended from (I).  So that we here have many species descended from a
+single progenitor grouped into genera; and the genera are included in, or
+subordinate to, sub-families, families, and orders, all united into one
+class.  Thus, the grand fact in natural history of the subordination of
+group under group, which, from its familiarity, does not always
+sufficiently strike us, is in my judgment fully explained.
+</para>
+
+<para>
+Naturalists try to arrange the species, genera, and families in each class,
+on what is called the Natural System.  But what is meant by this system? 
+Some authors look at it merely as a scheme for arranging together those
+living objects which are most alike, and for separating those which are
+most unlike; or as an artificial means for enunciating, as briefly as
+possible, general propositions,--that is, by one sentence to give the
+characters common, for instance, to all mammals, by another those common to
+all carnivora, by another those common to the dog-genus, and then by adding
+a single sentence, a full description is given of each kind of dog.  The
+ingenuity and utility of this system are indisputable.  But many
+naturalists think that something more is meant by the Natural System; they
+believe that it reveals the plan of the Creator; but unless it be specified
+whether order in time or space, or what else is meant by the plan of the
+Creator, it seems to me that nothing is thus added to our knowledge.  Such
+expressions as that famous one of Linnaeus, and which we often meet with in
+a more or less concealed form, that the characters do not make the genus,
+but that the genus gives the characters, seem to imply that something more
+is included in our classification, than mere resemblance.  I believe that
+something more is included; and that propinquity of descent,--the only
+known cause of the similarity of organic beings,--is the bond, hidden as it
+is by various degrees of modification, which is partially revealed to us by
+our classifications.
+</para>
+
+<para>
+Let us now consider the rules followed in classification, and the
+difficulties which are encountered on the view that classification either
+gives some unknown plan of creation, or is simply a scheme for enunciating
+general propositions and of placing together the forms most like each
+other.  It might have been thought (and was in ancient times thought) that
+those parts of the structure which determined the habits of life, and the
+general place of each being in the economy of nature, would be of very high
+importance in classification.  Nothing can be more false.  No one regards
+the external similarity of a mouse to a shrew, of a dugong to a whale, of a
+whale to a fish, as of any importance.  These resemblances, though so
+intimately connected with the whole life of the being, are ranked as merely
+'adaptive or analogical characters;' but to the consideration of these
+resemblances we shall have to recur.  It may even be given as a general
+rule, that the less any part of the organisation is concerned with special
+habits, the more important it becomes for classification.  As an instance: 
+Owen, in speaking of the dugong, says, 'The generative organs being those
+which are most remotely related to the habits and food of an animal, I have
+always regarded as affording very clear indications of its true affinities. 
+We are least likely in the modifications of these organs to mistake a
+merely adaptive for an essential character.'  So with plants, how
+remarkable it is that the organs of vegetation, on which their whole life
+depends, are of little signification, excepting in the first main
+divisions; whereas the organs of reproduction, with their product the seed,
+are of paramount importance!
+</para>
+
+<para>
+We must not, therefore, in classifying, trust to resemblances in parts of
+the organisation, however important they may be for the welfare of the
+being in relation to the outer world.  Perhaps from this cause it has
+partly arisen, that almost all naturalists lay the greatest stress on
+resemblances in organs of high vital or physiological importance.  No doubt
+this view of the classificatory importance of organs which are important is
+generally, but by no means always, true.  But their importance for
+classification, I believe, depends on their greater constancy throughout
+large groups of species; and this constancy depends on such organs having
+generally been subjected to less change in the adaptation of the species to
+their conditions of life.  That the mere physiological importance of an
+organ does not determine its classificatory value, is almost shown by the
+one fact, that in allied groups, in which the same organ, as we have every
+reason to suppose, has nearly the same physiological value, its
+classificatory value is widely different.  No naturalist can have worked at
+any group without being struck with this fact; and it has been most fully
+acknowledged in the writings of almost every author.  It will suffice to
+quote the highest authority, Robert Brown, who in speaking of certain
+organs in the Proteaceae, says their generic importance, 'like that of all
+their parts, not only in this but, as I apprehend, in every natural family,
+is very unequal, and in some cases seems to be entirely lost.'  Again in
+another work he says, the genera of the Connaraceae 'differ in having one
+or more ovaria, in the existence or absence of albumen, in the imbricate or
+valvular aestivation.  Any one of these characters singly is frequently of
+more than generic importance, though here even when all taken together they
+appear insufficient to separate Cnestis from Connarus.'  To give an example
+amongst insects, in one great division of the Hymenoptera, the antennae, as
+Westwood has remarked, are most constant in structure; in another division
+they differ much, and the differences are of quite subordinate value in
+classification; yet no one probably will say that the antennae in these two
+divisions of the same order are of unequal physiological importance.  Any
+number of instances could be given of the varying importance for
+classification of the same important organ within the same group of beings.
+</para>
+
+<para>
+Again, no one will say that rudimentary or atrophied organs are of high
+physiological or vital importance; yet, undoubtedly, organs in this
+condition are often of high value in classification.  No one will dispute
+that the rudimentary teeth in the upper jaws of young ruminants, and
+certain rudimentary bones of the leg, are highly serviceable in exhibiting
+the close affinity between Ruminants and Pachyderms.  Robert Brown has
+strongly insisted on the fact that the rudimentary florets are of the
+highest importance in the classification of the Grasses.
+</para>
+
+<para>
+Numerous instances could be given of characters derived from parts which
+must be considered of very trifling physiological importance, but which are
+universally admitted as highly serviceable in the definition of whole
+groups.  For instance, whether or not there is an open passage from the
+nostrils to the mouth, the only character, according to Owen, which
+absolutely distinguishes fishes and reptiles--the inflection of the angle
+of the jaws in Marsupials--the manner in which the wings of insects are
+folded--mere colour in certain Algae--mere pubescence on parts of the
+flower in grasses--the nature of the dermal covering, as hair or feathers,
+in the Vertebrata.  If the Ornithorhynchus had been covered with feathers
+instead of hair, this external and trifling character would, I think, have
+been considered by naturalists as important an aid in determining the
+degree of affinity of this strange creature to birds and reptiles, as an
+approach in structure in any one internal and important organ.
+</para>
+
+<para>
+The importance, for classification, of trifling characters, mainly depends
+on their being correlated with several other characters of more or less
+importance.  The value indeed of an aggregate of characters is very evident
+in natural history.  Hence, as has often been remarked, a species may
+depart from its allies in several characters, both of high physiological
+importance and of almost universal prevalence, and yet leave us in no doubt
+where it should be ranked.  Hence, also, it has been found, that a
+classification founded on any single character, however important that may
+be, has always failed; for no part of the organisation is universally
+constant.  The importance of an aggregate of characters, even when none are
+important, alone explains, I think, that saying of Linnaeus, that the
+characters do not give the genus, but the genus gives the characters; for
+this saying seems founded on an appreciation of many trifling points of
+resemblance, too slight to be defined.  Certain plants, belonging to the
+Malpighiaceae, bear perfect and degraded flowers; in the latter, as A. de
+Jussieu has remarked, 'the greater number of the characters proper to the
+species, to the genus, to the family, to the class, disappear, and thus
+laugh at our classification.'  But when Aspicarpa produced in France,
+during several years, only degraded flowers, departing so wonderfully in a
+number of the most important points of structure from the proper type of
+the order, yet M. Richard sagaciously saw, as Jussieu observes, that this
+genus should still be retained amongst the Malpighiaceae.  This case seems
+to me well to illustrate the spirit with which our classifications are
+sometimes necessarily founded.
+</para>
+
+<para>
+Practically when naturalists are at work, they do not trouble themselves
+about the physiological value of the characters which they use in defining
+a group, or in allocating any particular species.  If they find a character
+nearly uniform, and common to a great number of forms, and not common to
+others, they use it as one of high value; if common to some lesser number,
+they use it as of subordinate value.  This principle has been broadly
+confessed by some naturalists to be the true one; and by none more clearly
+than by that excellent botanist, Aug. St. Hilaire.  If certain characters
+are always found correlated with others, though no apparent bond of
+connexion can be discovered between them, especial value is set on them. 
+As in most groups of animals, important organs, such as those for
+propelling the blood, or for aerating it, or those for propagating the
+race, are found nearly uniform, they are considered as highly serviceable
+in classification; but in some groups of animals all these, the most
+important vital organs, are found to offer characters of quite subordinate
+value.
+</para>
+
+<para>
+We can see why characters derived from the embryo should be of equal
+importance with those derived from the adult, for our classifications of
+course include all ages of each species.  But it is by no means obvious, on
+the ordinary view, why the structure of the embryo should be more important
+for this purpose than that of the adult, which alone plays its full part in
+the economy of nature.  Yet it has been strongly urged by those great
+naturalists, Milne Edwards and Agassiz, that embryonic characters are the
+most important of any in the classification of animals; and this doctrine
+has very generally been admitted as true.  The same fact holds good with
+flowering plants, of which the two main divisions have been founded on
+characters derived from the embryo,--on the number and position of the
+embryonic leaves or cotyledons, and on the mode of development of the
+plumule and radicle.  In our discussion on embryology, we shall see why
+such characters are so valuable, on the view of classification tacitly
+including the idea of descent.
+</para>
+
+<para>
+Our classifications are often plainly influenced by chains of affinities. 
+Nothing can be easier than to define a number of characters common to all
+birds; but in the case of crustaceans, such definition has hitherto been
+found impossible.  There are crustaceans at the opposite ends of the
+series, which have hardly a character in common; yet the species at both
+ends, from being plainly allied to others, and these to others, and so
+onwards, can be recognised as unequivocally belonging to this, and to no
+other class of the Articulata.
+</para>
+
+<para>
+Geographical distribution has often been used, though perhaps not quite
+logically, in classification, more especially in very large groups of
+closely allied forms.  Temminck insists on the utility or even necessity of
+this practice in certain groups of birds; and it has been followed by
+several entomologists and botanists.
+</para>
+
+<para>
+Finally, with respect to the comparative value of the various groups of
+species, such as orders, sub-orders, families, sub-families, and genera,
+they seem to be, at least at present, almost arbitrary.  Several of the
+best botanists, such as Mr. Bentham and others, have strongly insisted on
+their arbitrary value.  Instances could be given amongst plants and
+insects, of a group of forms, first ranked by practised naturalists as only
+a genus, and then raised to the rank of a sub-family or family; and this
+has been done, not because further research has detected important
+structural differences, at first overlooked, but because numerous allied
+species, with slightly different grades of difference, have been
+subsequently discovered.
+</para>
+	
+<para>
+All the foregoing rules and aids and difficulties in classification are
+explained, if I do not greatly deceive myself, on the view that the natural
+system is founded on descent with modification; that the characters which
+naturalists consider as showing true affinity between any two or more
+species, are those which have been inherited from a common parent, and, in
+so far, all true classification is genealogical; that community of descent
+is the hidden bond which naturalists have been unconsciously seeking, and
+not some unknown plan of creation, or the enunciation of general
+propositions, and the mere putting together and separating objects more or
+less alike.
+</para>
+
+<para>
+But I must explain my meaning more fully.  I believe that the arrangement
+of the groups within each class, in due subordination and relation to the
+other groups, must be strictly genealogical in order to be natural; but
+that the amount of difference in the several branches or groups, though
+allied in the same degree in blood to their common progenitor, may differ
+greatly, being due to the different degrees of modification which they have
+undergone; and this is expressed by the forms being ranked under different
+genera, families, sections, or orders.  The reader will best understand
+what is meant, if he will take the trouble of referring to the diagram in
+the fourth chapter.  We will suppose the letters A to L to represent allied
+genera, which lived during the Silurian epoch, and these have descended
+from a species which existed at an unknown anterior period.  Species of
+three of these genera (A, F, and I) have transmitted modified descendants
+to the present day, represented by the fifteen genera (a14 to z14) on the
+uppermost horizontal line.  Now all these modified descendants from a
+single species, are represented as related in blood or descent to the same
+degree; they may metaphorically be called cousins to the same millionth
+degree; yet they differ widely and in different degrees from each other. 
+The forms descended from A, now broken up into two or three families,
+constitute a distinct order from those descended from I, also broken up
+into two families.  Nor can the existing species, descended from A, be
+ranked in the same genus with the parent A; or those from I, with the
+parent I.  But the existing genus F14 may be supposed to have been but
+slightly modified; and it will then rank with the parent-genus F; just as
+some few still living organic beings belong to Silurian genera.  So that
+the amount or value of the differences between organic beings all related
+to each other in the same degree in blood, has come to be widely different. 
+Nevertheless their genealogical arrangement remains strictly true, not only
+at the present time, but at each successive period of descent.  All the
+modified descendants from A will have inherited something in common from
+their common parent, as will all the descendants from I; so will it be with
+each subordinate branch of descendants, at each successive period.  If,
+however, we choose to suppose that any of the descendants of A or of I have
+been so much modified as to have more or less completely lost traces of
+their parentage, in this case, their places in a natural classification
+will have been more or less completely lost,--as sometimes seems to have
+occurred with existing organisms.  All the descendants of the genus F,
+along its whole line of descent, are supposed to have been but little
+modified, and they yet form a single genus.  But this genus, though much
+isolated, will still occupy its proper intermediate position; for F
+originally was intermediate in character between A and I, and the several
+genera descended from these two genera will have inherited to a certain
+extent their characters.  This natural arrangement is shown, as far as is
+possible on paper, in the diagram, but in much too simple a manner.  If a
+branching diagram had not been used, and only the names of the groups had
+been written in a linear series, it would have been still less possible to
+have given a natural arrangement; and it is notoriously not possible to
+represent in a series, on a flat surface, the affinities which we discover
+in nature amongst the beings of the same group.  Thus, on the view which I
+hold, the natural system is genealogical in its arrangement, like a
+pedigree; but the degrees of modification which the different groups have
+undergone, have to be expressed by ranking them under different so-called
+genera, sub-families, families, sections, orders, and classes.
+</para>
+
+<para>
+It may be worth while to illustrate this view of classification, by taking
+the case of languages.  If we possessed a perfect pedigree of mankind, a
+genealogical arrangement of the races of man would afford the best
+classification of the various languages now spoken throughout the world;
+and if all extinct languages, and all intermediate and slowly changing
+dialects, had to be included, such an arrangement would, I think, be the
+only possible one.  Yet it might be that some very ancient language had
+altered little, and had given rise to few new languages, whilst others
+(owing to the spreading and subsequent isolation and states of civilisation
+of the several races, descended from a common race) had altered much, and
+had given rise to many new languages and dialects.  The various degrees of
+difference in the languages from the same stock, would have to be expressed
+by groups subordinate to groups; but the proper or even only possible
+arrangement would still be genealogical; and this would be strictly
+natural, as it would connect together all languages, extinct and modern, by
+the closest affinities, and would give the filiation and origin of each
+tongue.
+</para>
+
+<para>
+In confirmation of this view, let us glance at the classification of
+varieties, which are believed or known to have descended from one species. 
+These are grouped under species, with sub-varieties under varieties; and
+with our domestic productions, several other grades of difference are
+requisite, as we have seen with pigeons.  The origin of the existence of
+groups subordinate to groups, is the same with varieties as with species,
+namely, closeness of descent with various degrees of modification.  Nearly
+the same rules are followed in classifying varieties, as with species. 
+Authors have insisted on the necessity of classing varieties on a natural
+instead of an artificial system; we are cautioned, for instance, not to
+class two varieties of the pine-apple together, merely because their fruit,
+though the most important part, happens to be nearly identical; no one puts
+the swedish and common turnips together, though the esculent and thickened
+stems are so similar.  Whatever part is found to be most constant, is used
+in classing varieties:  thus the great agriculturist Marshall says the
+horns are very useful for this purpose with cattle, because they are less
+variable than the shape or colour of the body, &amp;c.; whereas with sheep the
+horns are much less serviceable, because less constant.  In classing
+varieties, I apprehend if we had a real pedigree, a genealogical
+classification would be universally preferred; and it has been attempted by
+some authors.  For we might feel sure, whether there had been more or less
+modification, the principle of inheritance would keep the forms together
+which were allied in the greatest number of points.  In tumbler pigeons,
+though some sub-varieties differ from the others in the important character
+of having a longer beak, yet all are kept together from having the common
+habit of tumbling; but the short-faced breed has nearly or quite lost this
+habit; nevertheless, without any reasoning or thinking on the subject,
+these tumblers are kept in the same group, because allied in blood and
+alike in some other respects.  If it could be proved that the Hottentot had
+descended from the Negro, I think he would be classed under the Negro
+group, however much he might differ in colour and other important
+characters from negroes.
+</para>
+
+<para>
+With species in a state of nature, every naturalist has in fact brought
+descent into his classification; for he includes in his lowest grade, or
+that of a species, the two sexes; and how enormously these sometimes differ
+in the most important characters, is known to every naturalist:  scarcely a
+single fact can be predicated in common of the males and hermaphrodites of
+certain cirripedes, when adult, and yet no one dreams of separating them. 
+The naturalist includes as one species the several larval stages of the
+same individual, however much they may differ from each other and from the
+adult; as he likewise includes the so-called alternate generations of
+Steenstrup, which can only in a technical sense be considered as the same
+individual.  He includes monsters; he includes varieties, not solely
+because they closely resemble the parent-form, but because they are
+descended from it.  He who believes that the cowslip is descended from the
+primrose, or conversely, ranks them together as a single species, and gives
+a single definition.  As soon as three Orchidean forms (Monochanthus,
+Myanthus, and Catasetum), which had previously been ranked as three
+distinct genera, were known to be sometimes produced on the same spike,
+they were immediately included as a single species.  But it may be asked,
+what ought we to do, if it could be proved that one species of kangaroo had
+been produced, by a long course of modification, from a bear?  Ought we to
+rank this one species with bears, and what should we do with the other
+species?  The supposition is of course preposterous; and I might answer by
+the argumentum ad hominem, and ask what should be done if a perfect
+kangaroo were seen to come out of the womb of a bear?  According to all
+analogy, it would be ranked with bears; but then assuredly all the other
+species of the kangaroo family would have to be classed under the bear
+genus.  The whole case is preposterous; for where there has been close
+descent in common, there will certainly be close resemblance or affinity.
+</para>
+
+<para>
+As descent has universally been used in classing together the individuals
+of the same species, though the males and females and larvae are sometimes
+extremely different; and as it has been used in classing varieties which
+have undergone a certain, and sometimes a considerable amount of
+modification, may not this same element of descent have been unconsciously
+used in grouping species under genera, and genera under higher groups,
+though in these cases the modification has been greater in degree, and has
+taken a longer time to complete?  I believe it has thus been unconsciously
+used; and only thus can I understand the several rules and guides which
+have been followed by our best systematists.  We have no written pedigrees;
+we have to make out community of descent by resemblances of any kind. 
+Therefore we choose those characters which, as far as we can judge, are the
+least likely to have been modified in relation to the conditions of life to
+which each species has been recently exposed.  Rudimentary structures on
+this view are as good as, or even sometimes better than, other parts of the
+organisation.  We care not how trifling a character may be--let it be the
+mere inflection of the angle of the jaw, the manner in which an insect's
+wing is folded, whether the skin be covered by hair or feathers--if it
+prevail throughout many and different species, especially those having very
+different habits of life, it assumes high value; for we can account for its
+presence in so many forms with such different habits, only by its
+inheritance from a common parent.  We may err in this respect in regard to
+single points of structure, but when several characters, let them be ever
+so trifling, occur together throughout a large group of beings having
+different habits, we may feel almost sure, on the theory of descent, that
+these characters have been inherited from a common ancestor.  And we know
+that such correlated or aggregated characters have especial value in
+classification.
+</para>
+
+<para>
+We can understand why a species or a group of species may depart, in
+several of its most important characteristics, from its allies, and yet be
+safely classed with them.  This may be safely done, and is often done, as
+long as a sufficient number of characters, let them be ever so unimportant,
+betrays the hidden bond of community of descent.  Let two forms have not a
+single character in common, yet if these extreme forms are connected
+together by a chain of intermediate groups, we may at once infer their
+community of descent, and we put them all into the same class.  As we find
+organs of high physiological importance--those which serve to preserve life
+under the most diverse conditions of existence--are generally the most
+constant, we attach especial value to them; but if these same organs, in
+another group or section of a group, are found to differ much, we at once
+value them less in our classification.  We shall hereafter, I think,
+clearly see why embryological characters are of such high classificatory
+importance.  Geographical distribution may sometimes be brought usefully
+into play in classing large and widely-distributed genera, because all the
+species of the same genus, inhabiting any distinct and isolated region,
+have in all probability descended from the same parents.
+</para>
+
+<para>
+We can understand, on these views, the very important distinction between
+real affinities and analogical or adaptive resemblances.  Lamarck first
+called attention to this distinction, and he has been ably followed by
+Macleay and others.  The resemblance, in the shape of the body and in the
+fin-like anterior limbs, between the dugong, which is a pachydermatous
+animal, and the whale, and between both these mammals and fishes, is
+analogical.  Amongst insects there are innumerable instances:  thus
+Linnaeus, misled by external appearances, actually classed an homopterous
+insect as a moth.  We see something of the same kind even in our domestic
+varieties, as in the thickened stems of the common and swedish turnip.  The
+resemblance of the greyhound and racehorse is hardly more fanciful than the
+analogies which have been drawn by some authors between very distinct
+animals.  On my view of characters being of real importance for
+classification, only in so far as they reveal descent, we can clearly
+understand why analogical or adaptive character, although of the utmost
+importance to the welfare of the being, are almost valueless to the
+systematist.  For animals, belonging to two most distinct lines of descent,
+may readily become adapted to similar conditions, and thus assume a close
+external resemblance; but such resemblances will not reveal--will rather
+tend to conceal their blood-relationship to their proper lines of descent. 
+We can also understand the apparent paradox, that the very same characters
+are analogical when one class or order is compared with another, but give
+true affinities when the members of the same class or order are compared
+one with another:  thus the shape of the body and fin-like limbs are only
+analogical when whales are compared with fishes, being adaptations in both
+classes for swimming through the water; but the shape of the body and
+fin-like limbs serve as characters exhibiting true affinity between the
+several members of the whale family; for these cetaceans agree in so many
+characters, great and small, that we cannot doubt that they have inherited
+their general shape of body and structure of limbs from a common ancestor. 
+So it is with fishes.
+</para>
+
+<para>
+As members of distinct classes have often been adapted by successive slight
+modifications to live under nearly similar circumstances,--to inhabit for
+instance the three elements of land, air, and water,--we can perhaps
+understand how it is that a numerical parallelism has sometimes been
+observed between the sub-groups in distinct classes.  A naturalist, struck
+by a parallelism of this nature in any one class, by arbitrarily raising or
+sinking the value of the groups in other classes (and all our experience
+shows that this valuation has hitherto been arbitrary), could easily extend
+the parallelism over a wide range; and thus the septenary, quinary,
+quaternary, and ternary classifications have probably arisen.
+</para>
+
+<para>
+As the modified descendants of dominant species, belonging to the larger
+genera, tend to inherit the advantages, which made the groups to which they
+belong large and their parents dominant, they are almost sure to spread
+widely, and to seize on more and more places in the economy of nature.  The
+larger and more dominant groups thus tend to go on increasing in size; and
+they consequently supplant many smaller and feebler groups.  Thus we can
+account for the fact that all organisms, recent and extinct, are included
+under a few great orders, under still fewer classes, and all in one great
+natural system.  As showing how few the higher groups are in number, and
+how widely spread they are throughout the world, the fact is striking, that
+the discovery of Australia has not added a single insect belonging to a new
+order; and that in the vegetable kingdom, as I learn from Dr. Hooker, it
+has added only two or three orders of small size.
+</para>
+
+<para>
+In the chapter on geological succession I attempted to show, on the
+principle of each group having generally diverged much in character during
+the long-continued process of modification, how it is that the more ancient
+forms of life often present characters in some slight degree intermediate
+between existing groups.  A few old and intermediate parent-forms having
+occasionally transmitted to the present day descendants but little
+modified, will give to us our so-called osculant or aberrant groups.  The
+more aberrant any form is, the greater must be the number of connecting
+forms which on my theory have been exterminated and utterly lost.  And we
+have some evidence of aberrant forms having suffered severely from
+extinction, for they are generally represented by extremely few species;
+and such species as do occur are generally very distinct from each other,
+which again implies extinction.  The genera Ornithorhynchus and
+Lepidosiren, for example, would not have been less aberrant had each been
+represented by a dozen species instead of by a single one; but such
+richness in species, as I find after some investigation, does not commonly
+fall to the lot of aberrant genera.  We can, I think, account for this fact
+only by looking at aberrant forms as failing groups conquered by more
+successful competitors, with a few members preserved by some unusual
+coincidence of favourable circumstances.
+</para>
+
+<para>
+Mr. Waterhouse has remarked that, when a member belonging to one group of
+animals exhibits an affinity to a quite distinct group, this affinity in
+most cases is general and not special:  thus, according to Mr. Waterhouse,
+of all Rodents, the bizcacha is most nearly related to Marsupials; but in
+the points in which it approaches this order, its relations are general,
+and not to any one marsupial species more than to another.  As the points
+of affinity of the bizcacha to Marsupials are believed to be real and not
+merely adaptive, they are due on my theory to inheritance in common. 
+Therefore we must suppose either that all Rodents, including the bizcacha,
+branched off from some very ancient Marsupial, which will have had a
+character in some degree intermediate with respect to all existing
+Marsupials; or that both Rodents and Marsupials branched off from a common
+progenitor, and that both groups have since undergone much modification in
+divergent directions.  On either view we may suppose that the bizcacha has
+retained, by inheritance, more of the character of its ancient progenitor
+than have other Rodents; and therefore it will not be specially related to
+any one existing Marsupial, but indirectly to all or nearly all Marsupials,
+from having partially retained the character of their common progenitor, or
+of an early member of the group.  On the other hand, of all Marsupials, as
+Mr. Waterhouse has remarked, the phascolomys resembles most nearly, not any
+one species, but the general order of Rodents.  In this case, however, it
+may be strongly suspected that the resemblance is only analogical, owing to
+the phascolomys having become adapted to habits like those of a Rodent. 
+The elder De Candolle has made nearly similar observations on the general
+nature of the affinities of distinct orders of plants.
+</para>
+
+<para>
+On the principle of the multiplication and gradual divergence in character
+of the species descended from a common parent, together with their
+retention by inheritance of some characters in common, we can understand
+the excessively complex and radiating affinities by which all the members
+of the same family or higher group are connected together.  For the common
+parent of a whole family of species, now broken up by extinction into
+distinct groups and sub-groups, will have transmitted some of its
+characters, modified in various ways and degrees, to all; and the several
+species will consequently be related to each other by circuitous lines of
+affinity of various lengths (as may be seen in the diagram so often
+referred to), mounting up through many predecessors.  As it is difficult to
+show the blood-relationship between the numerous kindred of any ancient and
+noble family, even by the aid of a genealogical tree, and almost impossible
+to do this without this aid, we can understand the extraordinary difficulty
+which naturalists have experienced in describing, without the aid of a
+diagram, the various affinities which they perceive between the many living
+and extinct members of the same great natural class.
+</para>
+
+<para>
+Extinction, as we have seen in the fourth chapter, has played an important
+part in defining and widening the intervals between the several groups in
+each class.  We may thus account even for the distinctness of whole classes
+from each other--for instance, of birds from all other vertebrate
+animals--by the belief that many ancient forms of life have been utterly
+lost, through which the early progenitors of birds were formerly connected
+with the early progenitors of the other vertebrate classes.  There has been
+less entire extinction of the forms of life which once connected fishes
+with batrachians.  There has been still less in some other classes, as in
+that of the Crustacea, for here the most wonderfully diverse forms are
+still tied together by a long, but broken, chain of affinities.  Extinction
+has only separated groups:  it has by no means made them; for if every form
+which has ever lived on this earth were suddenly to reappear, though it
+would be quite impossible to give definitions by which each group could be
+distinguished from other groups, as all would blend together by steps as
+fine as those between the finest existing varieties, nevertheless a natural
+classification, or at least a natural arrangement, would be possible.  We
+shall see this by turning to the diagram:  the letters, A to L, may
+represent eleven Silurian genera, some of which have produced large groups
+of modified descendants.  Every intermediate link between these eleven
+genera and their primordial parent, and every intermediate link in each
+branch and sub-branch of their descendants, may be supposed to be still
+alive; and the links to be as fine as those between the finest varieties. 
+In this case it would be quite impossible to give any definition by which
+the several members of the several groups could be distinguished from their
+more immediate parents; or these parents from their ancient and unknown
+progenitor.  Yet the natural arrangement in the diagram would still hold
+good; and, on the principle of inheritance, all the forms descended from A,
+or from I, would have something in common.  In a tree we can specify this
+or that branch, though at the actual fork the two unite and blend together. 
+We could not, as I have said, define the several groups; but we could pick
+out types, or forms, representing most of the characters of each group,
+whether large or small, and thus give a general idea of the value of the
+differences between them.  This is what we should be driven to, if we were
+ever to succeed in collecting all the forms in any class which have lived
+throughout all time and space.  We shall certainly never succeed in making
+so perfect a collection:  nevertheless, in certain classes, we are tending
+in this direction; and Milne Edwards has lately insisted, in an able paper,
+on the high importance of looking to types, whether or not we can separate
+and define the groups to which such types belong.
+</para>
+
+<para>
+Finally, we have seen that natural selection, which results from the
+struggle for existence, and which almost inevitably induces extinction and
+divergence of character in the many descendants from one dominant
+parent-species, explains that great and universal feature in the affinities
+of all organic beings, namely, their subordination in group under group. 
+We use the element of descent in classing the individuals of both sexes and
+of all ages, although having few characters in common, under one species;
+we use descent in classing acknowledged varieties, however different they
+may be from their parent; and I believe this element of descent is the
+hidden bond of connexion which naturalists have sought under the term of
+the Natural System.  On this idea of the natural system being, in so far as
+it has been perfected, genealogical in its arrangement, with the grades of
+difference between the descendants from a common parent, expressed by the
+terms genera, families, orders, &amp;c., we can understand the rules which we
+are compelled to follow in our classification.  We can understand why we
+value certain resemblances far more than others; why we are permitted to
+use rudimentary and useless organs, or others of trifling physiological
+importance; why, in comparing one group with a distinct group, we summarily
+reject analogical or adaptive characters, and yet use these same characters
+within the limits of the same group.  We can clearly see how it is that all
+living and extinct forms can be grouped together in one great system; and
+how the several members of each class are connected together by the most
+complex and radiating lines of affinities.  We shall never, probably,
+disentangle the inextricable web of affinities between the members of any
+one class; but when we have a distinct object in view, and do not look to
+some unknown plan of creation, we may hope to make sure but slow progress.
+</para>
+
+<para>
+Morphology. -- We have seen that the members of the same class,
+independently of their habits of life, resemble each other in the general
+plan of their organisation.  This resemblance is often expressed by the
+term 'unity of type;' or by saying that the several parts and organs in the
+different species of the class are homologous.  The whole subject is
+included under the general name of Morphology.  This is the most
+interesting department of natural history, and may be said to be its very
+soul.  What can be more curious than that the hand of a man, formed for
+grasping, that of a mole for digging, the leg of the horse, the paddle of
+the porpoise, and the wing of the bat, should all be constructed on the
+same pattern, and should include the same bones, in the same relative
+positions?  Geoffroy St. Hilaire has insisted strongly on the high
+importance of relative connexion in homologous organs:  the parts may
+change to almost any extent in form and size, and yet they always remain
+connected together in the same order.  We never find, for instance, the
+bones of the arm and forearm, or of the thigh and leg, transposed.  Hence
+the same names can be given to the homologous bones in widely different
+animals.  We see the same great law in the construction of the mouths of
+insects:  what can be more different than the immensely long spiral
+proboscis of a sphinx-moth, the curious folded one of a bee or bug, and the
+great jaws of a beetle?--yet all these organs, serving for such different
+purposes, are formed by infinitely numerous modifications of an upper lip,
+mandibles, and two pairs of maxillae.  Analogous laws govern the
+construction of the mouths and limbs of crustaceans.  So it is with the
+flowers of plants.
+</para>
+
+<para>
+Nothing can be more hopeless than to attempt to explain this similarity of
+pattern in members of the same class, by utility or by the doctrine of
+final causes.  The hopelessness of the attempt has been expressly admitted
+by Owen in his most interesting work on the 'Nature of Limbs.'  On the
+ordinary view of the independent creation of each being, we can only say
+that so it is;--that it has so pleased the Creator to construct each animal
+and plant.
+</para>
+
+<para>
+The explanation is manifest on the theory of the natural selection of
+successive slight modifications,--each modification being profitable in
+some way to the modified form, but often affecting by correlation of growth
+other parts of the organisation.  In changes of this nature, there will be
+little or no tendency to modify the original pattern, or to transpose
+parts.  The bones of a limb might be shortened and widened to any extent,
+and become gradually enveloped in thick membrane, so as to serve as a fin;
+or a webbed foot might have all its bones, or certain bones, lengthened to
+any extent, and the membrane connecting them increased to any extent, so as
+to serve as a wing:  yet in all this great amount of modification there
+will be no tendency to alter the framework of bones or the relative
+connexion of the several parts.  If we suppose that the ancient progenitor,
+the archetype as it may be called, of all mammals, had its limbs
+constructed on the existing general pattern, for whatever purpose they
+served, we can at once perceive the plain signification of the homologous
+construction of the limbs throughout the whole class.  So with the mouths
+of insects, we have only to suppose that their common progenitor had an
+upper lip, mandibles, and two pair of maxillae, these parts being perhaps
+very simple in form; and then natural selection will account for the
+infinite diversity in structure and function of the mouths of insects. 
+Nevertheless, it is conceivable that the general pattern of an organ might
+become so much obscured as to be finally lost, by the atrophy and
+ultimately by the complete abortion of certain parts, by the soldering
+together of other parts, and by the doubling or multiplication of
+others,--variations which we know to be within the limits of possibility. 
+In the paddles of the extinct gigantic sea-lizards, and in the mouths of
+certain suctorial crustaceans, the general pattern seems to have been thus
+to a certain extent obscured.
+</para>
+
+<para>
+There is another and equally curious branch of the present subject; namely,
+the comparison not of the same part in different members of a class, but of
+the different parts or organs in the same individual.  Most physiologists
+believe that the bones of the skull are homologous with--that is correspond
+in number and in relative connexion with--the elemental parts of a certain
+number of vertebrae.  The anterior and posterior limbs in each member of
+the vertebrate and articulate classes are plainly homologous.  We see the
+same law in comparing the wonderfully complex jaws and legs in crustaceans. 
+It is familiar to almost every one, that in a flower the relative position
+of the sepals, petals, stamens, and pistils, as well as their intimate
+structure, are intelligible on the view that they consist of metamorphosed
+leaves, arranged in a spire.  In monstrous plants, we often get direct
+evidence of the possibility of one organ being transformed into another;
+and we can actually see in embryonic crustaceans and in many other animals,
+and in flowers, that organs, which when mature become extremely different,
+are at an early stage of growth exactly alike.
+</para>
+
+<para>
+How inexplicable are these facts on the ordinary view of creation!  Why
+should the brain be enclosed in a box composed of such numerous and such
+extraordinarily shaped pieces of bone?  As Owen has remarked, the benefit
+derived from the yielding of the separate pieces in the act of parturition
+of mammals, will by no means explain the same construction in the skulls of
+birds.  Why should similar bones have been created in the formation of the
+wing and leg of a bat, used as they are for such totally different
+purposes?  Why should one crustacean, which has an extremely complex mouth
+formed of many parts, consequently always have fewer legs; or conversely,
+those with many legs have simpler mouths?  Why should the sepals, petals,
+stamens, and pistils in any individual flower, though fitted for such
+widely different purposes, be all constructed on the same pattern?
+</para>
+
+<para>
+On the theory of natural selection, we can satisfactorily answer these
+questions.  In the vertebrata, we see a series of internal vertebrae
+bearing certain processes and appendages; in the articulata, we see the
+body divided into a series of segments, bearing external appendages; and in
+flowering plants, we see a series of successive spiral whorls of leaves. 
+An indefinite repetition of the same part or organ is the common
+characteristic (as Owen has observed) of all low or little-modified forms;
+therefore we may readily believe that the unknown progenitor of the
+vertebrata possessed many vertebrae; the unknown progenitor of the
+articulata, many segments; and the unknown progenitor of flowering plants,
+many spiral whorls of leaves.  We have formerly seen that parts many times
+repeated are eminently liable to vary in number and structure; consequently
+it is quite probable that natural selection, during a long-continued course
+of modification, should have seized on a certain number of the primordially
+similar elements, many times repeated, and have adapted them to the most
+diverse purposes.  And as the whole amount of modification will have been
+effected by slight successive steps, we need not wonder at discovering in
+such parts or organs, a certain degree of fundamental resemblance, retained
+by the strong principle of inheritance.
+</para>
+
+<para>
+In the great class of molluscs, though we can homologise the parts of one
+species with those of another and distinct species, we can indicate but few
+serial homologies; that is, we are seldom enabled to say that one part or
+organ is homologous with another in the same individual.  And we can
+understand this fact; for in molluscs, even in the lowest members of the
+class, we do not find nearly so much indefinite repetition of any one part,
+as we find in the other great classes of the animal and vegetable kingdoms.
+</para>
+
+<para>
+Naturalists frequently speak of the skull as formed of metamorphosed
+vertebrae:  the jaws of crabs as metamorphosed legs; the stamens and
+pistils of flowers as metamorphosed leaves; but it would in these cases
+probably be more correct, as Professor Huxley has remarked, to speak of
+both skull and vertebrae, both jaws and legs, &amp;c.,--as having been
+metamorphosed, not one from the other, but from some common element. 
+Naturalists, however, use such language only in a metaphorical sense:  they
+are far from meaning that during a long course of descent, primordial
+organs of any kind--vertebrae in the one case and legs in the other--have
+actually been modified into skulls or jaws.  Yet so strong is the
+appearance of a modification of this nature having occurred, that
+naturalists can hardly avoid employing language having this plain
+signification.  On my view these terms may be used literally; and the
+wonderful fact of the jaws, for instance, of a crab retaining numerous
+characters, which they would probably have retained through inheritance, if
+they had really been metamorphosed during a long course of descent from
+true legs, or from some simple appendage, is explained.
+</para>
+
+<para>
+Embryology. -- It has already been casually remarked that certain organs in
+the individual, which when mature become widely different and serve for
+different purposes, are in the embryo exactly alike.  The embryos, also, of
+distinct animals within the same class are often strikingly similar:  a
+better proof of this cannot be given, than a circumstance mentioned by
+Agassiz, namely, that having forgotten to ticket the embryo of some
+vertebrate animal, he cannot now tell whether it be that of a mammal, bird,
+or reptile.  The vermiform larvae of moths, flies, beetles, &amp;c., resemble
+each other much more closely than do the mature insects; but in the case of
+larvae, the embryos are active, and have been adapted for special lines of
+life.  A trace of the law of embryonic resemblance, sometimes lasts till a
+rather late age:  thus birds of the same genus, and of closely allied
+genera, often resemble each other in their first and second plumage; as we
+see in the spotted feathers in the thrush group.  In the cat tribe, most of
+the species are striped or spotted in lines; and stripes can be plainly
+distinguished in the whelp of the lion.  We occasionally though rarely see
+something of this kind in plants:  thus the embryonic leaves of the ulex or
+furze, and the first leaves of the phyllodineous acaceas, are pinnate or
+divided like the ordinary leaves of the leguminosae.
+</para>
+
+<para>
+The points of structure, in which the embryos of widely different animals
+of the same class resemble each other, often have no direct relation to
+their conditions of existence.  We cannot, for instance, suppose that in
+the embryos of the vertebrata the peculiar loop-like course of the arteries
+near the branchial slits are related to similar conditions,--in the young
+mammal which is nourished in the womb of its mother, in the egg of the bird
+which is hatched in a nest, and in the spawn of a frog under water.  We
+have no more reason to believe in such a relation, than we have to believe
+that the same bones in the hand of a man, wing of a bat, and fin of a
+porpoise, are related to similar conditions of life.  No one will suppose
+that the stripes on the whelp of a lion, or the spots on the young
+blackbird, are of any use to these animals, or are related to the
+conditions to which they are exposed.
+</para>
+
+<para>
+The case, however, is different when an animal during any part of its
+embryonic career is active, and has to provide for itself.  The period of
+activity may come on earlier or later in life; but whenever it comes on,
+the adaptation of the larva to its conditions of life is just as perfect
+and as beautiful as in the adult animal.  From such special adaptations,
+the similarity of the larvae or active embryos of allied animals is
+sometimes much obscured; and cases could be given of the larvae of two
+species, or of two groups of species, differing quite as much, or even
+more, from each other than do their adult parents.  In most cases, however,
+the larvae, though active, still obey more or less closely the law of
+common embryonic resemblance.  Cirripedes afford a good instance of this: 
+even the illustrious Cuvier did not perceive that a barnacle was, as it
+certainly is, a crustacean; but a glance at the larva shows this to be the
+case in an unmistakeable manner.  So again the two main divisions of
+cirripedes, the pedunculated and sessile, which differ widely in external
+appearance, have larvae in all their several stages barely distinguishable.
+</para>
+
+<para>
+The embryo in the course of development generally rises in organisation:  I
+use this expression, though I am aware that it is hardly possible to define
+clearly what is meant by the organisation being higher or lower.  But no
+one probably will dispute that the butterfly is higher than the
+caterpillar.  In some cases, however, the mature animal is generally
+considered as lower in the scale than the larva, as with certain parasitic
+crustaceans.  To refer once again to cirripedes:  the larvae in the first
+stage have three pairs of legs, a very simple single eye, and a
+probosciformed mouth, with which they feed largely, for they increase much
+in size.  In the second stage, answering to the chrysalis stage of
+butterflies, they have six pairs of beautifully constructed natatory legs,
+a pair of magnificent compound eyes, and extremely complex antennae; but
+they have a closed and imperfect mouth, and cannot feed:  their function at
+this stage is, to search by their well-developed organs of sense, and to
+reach by their active powers of swimming, a proper place on which to become
+attached and to undergo their final metamorphosis.  When this is completed
+they are fixed for life:  their legs are now converted into prehensile
+organs; they again obtain a well-constructed mouth; but they have no
+antennae, and their two eyes are now reconverted into a minute, single, and
+very simple eye-spot.  In this last and complete state, cirripedes may be
+considered as either more highly or more lowly organised than they were in
+the larval condition.  But in some genera the larvae become developed
+either into hermaphrodites having the ordinary structure, or into what I
+have called complemental males:  and in the latter, the development has
+assuredly been retrograde; for the male is a mere sack, which lives for a
+short time, and is destitute of mouth, stomach, or other organ of
+importance, excepting for reproduction.
+</para>
+
+<para>
+We are so much accustomed to see differences in structure between the
+embryo and the adult, and likewise a close similarity in the embryos of
+widely different animals within the same class, that we might be led to
+look at these facts as necessarily contingent in some manner on growth. 
+But there is no obvious reason why, for instance, the wing of a bat, or the
+fin of a porpoise, should not have been sketched out with all the parts in
+proper proportion, as soon as any structure became visible in the embryo. 
+And in some whole groups of animals and in certain members of other groups,
+the embryo does not at any period differ widely from the adult:  thus Owen
+has remarked in regard to cuttle-fish, 'there is no metamorphosis; the
+cephalopodic character is manifested long before the parts of the embryo
+are completed;' and again in spiders, 'there is nothing worthy to be called
+a metamorphosis.'  The larvae of insects, whether adapted to the most
+diverse and active habits, or quite inactive, being fed by their parents or
+placed in the midst of proper nutriment, yet nearly all pass through a
+similar worm-like stage of development; but in some few cases, as in that
+of Aphis, if we look to the admirable drawings by Professor Huxley of the
+development of this insect, we see no trace of the vermiform stage.
+</para>
+
+<para>
+How, then, can we explain these several facts in embryology,--namely the
+very general, but not universal difference in structure between the embryo
+and the adult;--of parts in the same individual embryo, which ultimately
+become very unlike and serve for diverse purposes, being at this early
+period of growth alike;--of embryos of different species within the same
+class, generally, but not universally, resembling each other;--of the
+structure of the embryo not being closely related to its conditions of
+existence, except when the embryo becomes at any period of life active and
+has to provide for itself;--of the embryo apparently having sometimes a
+higher organisation than the mature animal, into which it is developed.  I
+believe that all these facts can be explained, as follows, on the view of
+descent with modification.
+</para>
+
+<para>
+It is commonly assumed, perhaps from monstrosities often affecting the
+embryo at a very early period, that slight variations necessarily appear at
+an equally early period.  But we have little evidence on this head--indeed
+the evidence rather points the other way; for it is notorious that breeders
+of cattle, horses, and various fancy animals, cannot positively tell, until
+some time after the animal has been born, what its merits or form will
+ultimately turn out.  We see this plainly in our own children; we cannot
+always tell whether the child will be tall or short, or what its precise
+features will be.  The question is not, at what period of life any
+variation has been caused, but at what period it is fully displayed.  The
+cause may have acted, and I believe generally has acted, even before the
+embryo is formed; and the variation may be due to the male and female
+sexual elements having been affected by the conditions to which either
+parent, or their ancestors, have been exposed.  Nevertheless an effect thus
+caused at a very early period, even before the formation of the embryo, may
+appear late in life; as when an hereditary disease, which appears in old
+age alone, has been communicated to the offspring from the reproductive
+element of one parent.  Or again, as when the horns of cross-bred cattle
+have been affected by the shape of the horns of either parent.  For the
+welfare of a very young animal, as long as it remains in its mother's womb,
+or in the egg, or as long as it is nourished and protected by its parent,
+it must be quite unimportant whether most of its characters are fully
+acquired a little earlier or later in life.  It would not signify, for
+instance, to a bird which obtained its food best by having a long beak,
+whether or not it assumed a beak of this particular length, as long as it
+was fed by its parents.  Hence, I conclude, that it is quite possible, that
+each of the many successive modifications, by which each species has
+acquired its present structure, may have supervened at a not very early
+period of life; and some direct evidence from our domestic animals supports
+this view.  But in other cases it is quite possible that each successive
+modification, or most of them, may have appeared at an extremely early
+period.
+</para>
+
+<para>
+I have stated in the first chapter, that there is some evidence to render
+it probable, that at whatever age any variation first appears in the
+parent, it tends to reappear at a corresponding age in the offspring. 
+Certain variations can only appear at corresponding ages, for instance,
+peculiarities in the caterpillar, cocoon, or imago states of the silk-moth;
+or, again, in the horns of almost full-grown cattle.  But further than
+this, variations which, for all that we can see, might have appeared
+earlier or later in life, tend to appear at a corresponding age in the
+offspring and parent.  I am far from meaning that this is invariably the
+case; and I could give a good many cases of variations (taking the word in
+the largest sense) which have supervened at an earlier age in the child
+than in the parent.
+</para>
+
+<para>
+These two principles, if their truth be admitted, will, I believe, explain
+all the above specified leading facts in embryology.  But first let us look
+at a few analogous cases in domestic varieties.  Some authors who have
+written on Dogs, maintain that the greyhound and bulldog, though appearing
+so different, are really varieties most closely allied, and have probably
+descended from the same wild stock; hence I was curious to see how far
+their puppies differed from each other:  I was told by breeders that they
+differed just as much as their parents, and this, judging by the eye,
+seemed almost to be the case; but on actually measuring the old dogs and
+their six-days old puppies, I found that the puppies had not nearly
+acquired their full amount of proportional difference.  So, again, I was
+told that the foals of cart and race-horses differed as much as the
+full-grown animals; and this surprised me greatly, as I think it probable
+that the difference between these two breeds has been wholly caused by
+selection under domestication; but having had careful measurements made of
+the dam and of a three-days old colt of a race and heavy cart-horse, I find
+that the colts have by no means acquired their full amount of proportional
+difference.
+</para>
+
+<para>
+As the evidence appears to me conclusive, that the several domestic breeds
+of Pigeon have descended from one wild species, I compared young pigeons of
+various breeds, within twelve hours after being hatched; I carefully
+measured the proportions (but will not here give details) of the beak,
+width of mouth, length of nostril and of eyelid, size of feet and length of
+leg, in the wild stock, in pouters, fantails, runts, barbs, dragons,
+carriers, and tumblers.  Now some of these birds, when mature, differ so
+extraordinarily in length and form of beak, that they would, I cannot
+doubt, be ranked in distinct genera, had they been natural productions. 
+But when the nestling birds of these several breeds were placed in a row,
+though most of them could be distinguished from each other, yet their
+proportional differences in the above specified several points were
+incomparably less than in the full-grown birds.  Some characteristic points
+of difference--for instance, that of the width of mouth--could hardly be
+detected in the young.  But there was one remarkable exception to this
+rule, for the young of the short-faced tumbler differed from the young of
+the wild rock-pigeon and of the other breeds, in all its proportions,
+almost exactly as much as in the adult state.
+</para>
+
+<para>
+The two principles above given seem to me to explain these facts in regard
+to the later embryonic stages of our domestic varieties.  Fanciers select
+their horses, dogs, and pigeons, for breeding, when they are nearly grown
+up:  they are indifferent whether the desired qualities and structures have
+been acquired earlier or later in life, if the full-grown animal possesses
+them.  And the cases just given, more especially that of pigeons, seem to
+show that the characteristic differences which give value to each breed,
+and which have been accumulated by man's selection, have not generally
+first appeared at an early period of life, and have been inherited by the
+offspring at a corresponding not early period.  But the case of the
+short-faced tumbler, which when twelve hours old had acquired its proper
+proportions, proves that this is not the universal rule; for here the
+characteristic differences must either have appeared at an earlier period
+than usual, or, if not so, the differences must have been inherited, not at
+the corresponding, but at an earlier age.
+</para>
+
+<para>
+Now let us apply these facts and the above two principles--which latter,
+though not proved true, can be shown to be in some degree probable--to
+species in a state of nature.  Let us take a genus of birds, descended on
+my theory from some one parent-species, and of which the several new
+species have become modified through natural selection in accordance with
+their diverse habits.  Then, from the many slight successive steps of
+variation having supervened at a rather late age, and having been inherited
+at a corresponding age, the young of the new species of our supposed genus
+will manifestly tend to resemble each other much more closely than do the
+adults, just as we have seen in the case of pigeons.  We may extend this
+view to whole families or even classes.  The fore-limbs, for instance,
+which served as legs in the parent-species, may become, by a long course of
+modification, adapted in one descendant to act as hands, in another as
+paddles, in another as wings; and on the above two principles--namely of
+each successive modification supervening at a rather late age, and being
+inherited at a corresponding late age--the fore-limbs in the embryos of the
+several descendants of the parent-species will still resemble each other
+closely, for they will not have been modified.  But in each individual new
+species, the embryonic fore-limbs will differ greatly from the fore-limbs
+in the mature animal; the limbs in the latter having undergone much
+modification at a rather late period of life, and having thus been
+converted into hands, or paddles, or wings.  Whatever influence
+long-continued exercise or use on the one hand, and disuse on the other,
+may have in modifying an organ, such influence will mainly affect the
+mature animal, which has come to its full powers of activity and has to
+gain its own living; and the effects thus produced will be inherited at a
+corresponding mature age.  Whereas the young will remain unmodified, or be
+modified in a lesser degree, by the effects of use and disuse.
+</para>
+
+<para>
+In certain cases the successive steps of variation might supervene, from
+causes of which we are wholly ignorant, at a very early period of life, or
+each step might be inherited at an earlier period than that at which it
+first appeared.  In either case (as with the short-faced tumbler) the young
+or embryo would closely resemble the mature parent-form.  We have seen that
+this is the rule of development in certain whole groups of animals, as with
+cuttle-fish and spiders, and with a few members of the great class of
+insects, as with Aphis.  With respect to the final cause of the young in
+these cases not undergoing any metamorphosis, or closely resembling their
+parents from their earliest age, we can see that this would result from the
+two following contingencies; firstly, from the young, during a course of
+modification carried on for many generations, having to provide for their
+own wants at a very early stage of development, and secondly, from their
+following exactly the same habits of life with their parents; for in this
+case, it would be indispensable for the existence of the species, that the
+child should be modified at a very early age in the same manner with its
+parents, in accordance with their similar habits.  Some further
+explanation, however, of the embryo not undergoing any metamorphosis is
+perhaps requisite.  If, on the other hand, it profited the young to follow
+habits of life in any degree different from those of their parent, and
+consequently to be constructed in a slightly different manner, then, on the
+principle of inheritance at corresponding ages, the active young or larvae
+might easily be rendered by natural selection different to any conceivable
+extent from their parents.  Such differences might, also, become correlated
+with successive stages of development; so that the larvae, in the first
+stage, might differ greatly from the larvae in the second stage, as we have
+seen to be the case with cirripedes.  The adult might become fitted for
+sites or habits, in which organs of locomotion or of the senses, &amp;c., would
+be useless; and in this case the final metamorphosis would be said to be
+retrograde.
+</para>
+
+<para>
+As all the organic beings, extinct and recent, which have ever lived on
+this earth have to be classed together, and as all have been connected by
+the finest gradations, the best, or indeed, if our collections were nearly
+perfect, the only possible arrangement, would be genealogical.  Descent
+being on my view the hidden bond of connexion which naturalists have been
+seeking under the term of the natural system.  On this view we can
+understand how it is that, in the eyes of most naturalists, the structure
+of the embryo is even more important for classification than that of the
+adult.  For the embryo is the animal in its less modified state; and in so
+far it reveals the structure of its progenitor.  In two groups of animal,
+however much they may at present differ from each other in structure and
+habits, if they pass through the same or similar embryonic stages, we may
+feel assured that they have both descended from the same or nearly similar
+parents, and are therefore in that degree closely related.  Thus, community
+in embryonic structure reveals community of descent.  It will reveal this
+community of descent, however much the structure of the adult may have been
+modified and obscured; we have seen, for instance, that cirripedes can at
+once be recognised by their larvae as belonging to the great class of
+crustaceans.  As the embryonic state of each species and group of species
+partially shows us the structure of their less modified ancient
+progenitors, we can clearly see why ancient and extinct forms of life
+should resemble the embryos of their descendants,--our existing species. 
+Agassiz believes this to be a law of nature; but I am bound to confess that
+I only hope to see the law hereafter proved true.  It can be proved true in
+those cases alone in which the ancient state, now supposed to be
+represented in many embryos, has not been obliterated, either by the
+successive variations in a long course of modification having supervened at
+a very early age, or by the variations having been inherited at an earlier
+period than that at which they first appeared.  It should also be borne in
+mind, that the supposed law of resemblance of ancient forms of life to the
+embryonic stages of recent forms, may be true, but yet, owing to the
+geological record not extending far enough back in time, may remain for a
+long period, or for ever, incapable of demonstration.
+</para>
+
+<para>
+Thus, as it seems to me, the leading facts in embryology, which are second
+in importance to none in natural history, are explained on the principle of
+slight modifications not appearing, in the many descendants from some one
+ancient progenitor, at a very early period in the life of each, though
+perhaps caused at the earliest, and being inherited at a corresponding not
+early period.  Embryology rises greatly in interest, when we thus look at
+the embryo as a picture, more or less obscured, of the common parent-form
+of each great class of animals.
+</para>
+
+<para>
+Rudimentary, atrophied, or aborted organs. -- Organs or parts in this
+strange condition, bearing the stamp of inutility, are extremely common
+throughout nature.  For instance, rudimentary mammae are very general in
+the males of mammals:  I presume that the 'bastard-wing' in birds may be
+safely considered as a digit in a rudimentary state:  in very many snakes
+one lobe of the lungs is rudimentary; in other snakes there are rudiments
+of the pelvis and hind limbs.  Some of the cases of rudimentary organs are
+extremely curious; for instance, the presence of teeth in foetal whales,
+which when grown up have not a tooth in their heads; and the presence of
+teeth, which never cut through the gums, in the upper jaws of our unborn
+calves.  It has even been stated on good authority that rudiments of teeth
+can be detected in the beaks of certain embryonic birds.  Nothing can be
+plainer than that wings are formed for flight, yet in how many insects do
+we see wings so reduced in size as to be utterly incapable of flight, and
+not rarely lying under wing-cases, firmly soldered together!
+</para>
+
+<para>
+The meaning of rudimentary organs is often quite unmistakeable:  for
+instance there are beetles of the same genus (and even of the same species)
+resembling each other most closely in all respects, one of which will have
+full-sized wings, and another mere rudiments of membrane; and here it is
+impossible to doubt, that the rudiments represent wings.  Rudimentary
+organs sometimes retain their potentiality, and are merely not developed: 
+this seems to be the case with the mammae of male mammals, for many
+instances are on record of these organs having become well developed in
+full-grown males, and having secreted milk.  So again there are normally
+four developed and two rudimentary teats in the udders of the genus Bos,
+but in our domestic cows the two sometimes become developed and give milk. 
+In individual plants of the same species the petals sometimes occur as mere
+rudiments, and sometimes in a well-developed state.  In plants with
+separated sexes, the male flowers often have a rudiment of a pistil; and
+Kolreuter found that by crossing such male plants with an hermaphrodite
+species, the rudiment of the pistil in the hybrid offspring was much
+increased in size; and this shows that the rudiment and the perfect pistil
+are essentially alike in nature.
+</para>
+
+<para>
+An organ serving for two purposes, may become rudimentary or utterly
+aborted for one, even the more important purpose; and remain perfectly
+efficient for the other.  Thus in plants, the office of the pistil is to
+allow the pollen-tubes to reach the ovules protected in the ovarium at its
+base.  The pistil consists of a stigma supported on the style; but in some
+Compositae, the male florets, which of course cannot be fecundated, have a
+pistil, which is in a rudimentary state, for it is not crowned with a
+stigma; but the style remains well developed, and is clothed with hairs as
+in other compositae, for the purpose of brushing the pollen out of the
+surrounding anthers.  Again, an organ may become rudimentary for its proper
+purpose, and be used for a distinct object:  in certain fish the
+swim-bladder seems to be rudimentary for its proper function of giving
+buoyancy, but has become converted into a nascent breathing organ or lung. 
+Other similar instances could be given.
+</para>
+
+<para>
+Rudimentary organs in the individuals of the same species are very liable
+to vary in degree of development and in other respects.  Moreover, in
+closely allied species, the degree to which the same organ has been
+rendered rudimentary occasionally differs much.  This latter fact is well
+exemplified in the state of the wings of the female moths in certain
+groups.  Rudimentary organs may be utterly aborted; and this implies, that
+we find in an animal or plant no trace of an organ, which analogy would
+lead us to expect to find, and which is occasionally found in monstrous
+individuals of the species.  Thus in the snapdragon (antirrhinum) we
+generally do not find a rudiment of a fifth stamen; but this may sometimes
+be seen.  In tracing the homologies of the same part in different members
+of a class, nothing is more common, or more necessary, than the use and
+discovery of rudiments.  This is well shown in the drawings given by Owen
+of the bones of the leg of the horse, ox, and rhinoceros.
+</para>
+
+<para>
+It is an important fact that rudimentary organs, such as teeth in the upper
+jaws of whales and ruminants, can often be detected in the embryo, but
+afterwards wholly disappear.  It is also, I believe, a universal rule, that
+a rudimentary part or organ is of greater size relatively to the adjoining
+parts in the embryo, than in the adult; so that the organ at this early age
+is less rudimentary, or even cannot be said to be in any degree
+rudimentary.  Hence, also, a rudimentary organ in the adult, is often said
+to have retained its embryonic condition.
+</para>
+
+<para>
+I have now given the leading facts with respect to rudimentary organs.  In
+reflecting on them, every one must be struck with astonishment:  for the
+same reasoning power which tells us plainly that most parts and organs are
+exquisitely adapted for certain purposes, tells us with equal plainness
+that these rudimentary or atrophied organs, are imperfect and useless.  In
+works on natural history rudimentary organs are generally said to have been
+created 'for the sake of symmetry,' or in order 'to complete the scheme of
+nature;' but this seems to me no explanation, merely a restatement of the
+fact.  Would it be thought sufficient to say that because planets revolve
+in elliptic courses round the sun, satellites follow the same course round
+the planets, for the sake of symmetry, and to complete the scheme of
+nature?  An eminent physiologist accounts for the presence of rudimentary
+organs, by supposing that they serve to excrete matter in excess, or
+injurious to the system; but can we suppose that the minute papilla, which
+often represents the pistil in male flowers, and which is formed merely of
+cellular tissue, can thus act?  Can we suppose that the formation of
+rudimentary teeth which are subsequently absorbed, can be of any service to
+the rapidly growing embryonic calf by the excretion of precious phosphate
+of lime?  When a man's fingers have been amputated, imperfect nails
+sometimes appear on the stumps:  I could as soon believe that these
+vestiges of nails have appeared, not from unknown laws of growth, but in
+order to excrete horny matter, as that the rudimentary nails on the fin of
+the manatee were formed for this purpose.
+</para>
+
+<para>
+On my view of descent with modification, the origin of rudimentary organs
+is simple.  We have plenty of cases of rudimentary organs in our domestic
+productions,--as the stump of a tail in tailless breeds,--the vestige of an
+ear in earless breeds,--the reappearance of minute dangling horns in
+hornless breeds of cattle, more especially, according to Youatt, in young
+animals,--and the state of the whole flower in the cauliflower.  We often
+see rudiments of various parts in monsters.  But I doubt whether any of
+these cases throw light on the origin of rudimentary organs in a state of
+nature, further than by showing that rudiments can be produced; for I doubt
+whether species under nature ever undergo abrupt changes.  I believe that
+disuse has been the main agency; that it has led in successive generations
+to the gradual reduction of various organs, until they have become
+rudimentary,--as in the case of the eyes of animals inhabiting dark
+caverns, and of the wings of birds inhabiting oceanic islands, which have
+seldom been forced to take flight, and have ultimately lost the power of
+flying.  Again, an organ useful under certain conditions, might become
+injurious under others, as with the wings of beetles living on small and
+exposed islands; and in this case natural selection would continue slowly
+to reduce the organ, until it was rendered harmless and rudimentary.
+</para>
+
+<para>
+Any change in function, which can be effected by insensibly small steps, is
+within the power of natural selection; so that an organ rendered, during
+changed habits of life, useless or injurious for one purpose, might easily
+be modified and used for another purpose.  Or an organ might be retained
+for one alone of its former functions.  An organ, when rendered useless,
+may well be variable, for its variations cannot be checked by natural
+selection.  At whatever period of life disuse or selection reduces an
+organ, and this will generally be when the being has come to maturity and
+to its full powers of action, the principle of inheritance at corresponding
+ages will reproduce the organ in its reduced state at the same age, and
+consequently will seldom affect or reduce it in the embryo.  Thus we can
+understand the greater relative size of rudimentary organs in the embryo,
+and their lesser relative size in the adult.  But if each step of the
+process of reduction were to be inherited, not at the corresponding age,
+but at an extremely early period of life (as we have good reason to believe
+to be possible) the rudimentary part would tend to be wholly lost, and we
+should have a case of complete abortion.  The principle, also, of economy,
+explained in a former chapter, by which the materials forming any part or
+structure, if not useful to the possessor, will be saved as far as is
+possible, will probably often come into play; and this will tend to cause
+the entire obliteration of a rudimentary organ.
+</para>
+
+<para>
+As the presence of rudimentary organs is thus due to the tendency in every
+part of the organisation, which has long existed, to be inherited--we can
+understand, on the genealogical view of classification, how it is that
+systematists have found rudimentary parts as useful as, or even sometimes
+more useful than, parts of high physiological importance.  Rudimentary
+organs may be compared with the letters in a word, still retained in the
+spelling, but become useless in the pronunciation, but which serve as a
+clue in seeking for its derivation.  On the view of descent with
+modification, we may conclude that the existence of organs in a
+rudimentary, imperfect, and useless condition, or quite aborted, far from
+presenting a strange difficulty, as they assuredly do on the ordinary
+doctrine of creation, might even have been anticipated, and can be
+accounted for by the laws of inheritance.
+</para>
+
+<para>
+Summary. -- In this chapter I have attempted to show, that the
+subordination of group to group in all organisms throughout all time; that
+the nature of the relationship, by which all living and extinct beings are
+united by complex, radiating, and circuitous lines of affinities into one
+grand system; the rules followed and the difficulties encountered by
+naturalists in their classifications; the value set upon characters, if
+constant and prevalent, whether of high vital importance, or of the most
+trifling importance, or, as in rudimentary organs, of no importance; the
+wide opposition in value between analogical or adaptive characters, and
+characters of true affinity; and other such rules;--all naturally follow on
+the view of the common parentage of those forms which are considered by
+naturalists as allied, together with their modification through natural
+selection, with its contingencies of extinction and divergence of
+character.  In considering this view of classification, it should be borne
+in mind that the element of descent has been universally used in ranking
+together the sexes, ages, and acknowledged varieties of the same species,
+however different they may be in structure.  If we extend the use of this
+element of descent,--the only certainly known cause of similarity in
+organic beings,--we shall understand what is meant by the natural system: 
+it is genealogical in its attempted arrangement, with the grades of
+acquired difference marked by the terms varieties, species, genera,
+families, orders, and classes.
+</para>
+
+<para>
+On this same view of descent with modification, all the great facts in
+Morphology become intelligible,--whether we look to the same pattern
+displayed in the homologous organs, to whatever purpose applied, of the
+different species of a class; or to the homologous parts constructed on the
+same pattern in each individual animal and plant.
+</para>
+
+<para>
+On the principle of successive slight variations, not necessarily or
+generally supervening at a very early period of life, and being inherited
+at a corresponding period, we can understand the great leading facts in
+Embryology; namely, the resemblance in an individual embryo of the
+homologous parts, which when matured will become widely different from each
+other in structure and function; and the resemblance in different species
+of a class of the homologous parts or organs, though fitted in the adult
+members for purposes as different as possible.  Larvae are active embryos,
+which have become specially modified in relation to their habits of life,
+through the principle of modifications being inherited at corresponding
+ages.  On this same principle--and bearing in mind, that when organs are
+reduced in size, either from disuse or selection, it will generally be at
+that period of life when the being has to provide for its own wants, and
+bearing in mind how strong is the principle of inheritance--the occurrence
+of rudimentary organs and their final abortion, present to us no
+inexplicable difficulties; on the contrary, their presence might have been
+even anticipated.  The importance of embryological characters and of
+rudimentary organs in classification is intelligible, on the view that an
+arrangement is only so far natural as it is genealogical.
+</para>
+
+<para>
+Finally, the several classes of facts which have been considered in this
+chapter, seem to me to proclaim so plainly, that the innumerable species,
+genera, and families of organic beings, with which this world is peopled,
+have all descended, each within its own class or group, from common
+parents, and have all been modified in the course of descent, that I should
+without hesitation adopt this view, even if it were unsupported by other
+facts or arguments.
+</para>
+
+</chapter>
+
+<chapter>
+<chapheader>
+
+<chapnum>Chapter XIV</chapnum>
+
+<title>Recapitulation and Conclusion</title>
+
+<chapsummary>
+Recapitulation of the difficulties on the theory of Natural Selection --
+Recapitulation of the general and special circumstances in its favour --
+Causes of the general belief in the immutability of species -- How far the
+theory of natural selection may be extended -- Effects of its adoption on
+the study of Natural history -- Concluding remarks.
+</chapsummary>
+</chapheader>
+
+<para>
+As this whole volume is one long argument, it may be convenient to the
+reader to have the leading facts and inferences briefly recapitulated.
+</para>
+
+<para>
+That many and grave objections may be advanced against the theory of
+descent with modification through natural selection, I do not deny.  I have
+endeavoured to give to them their full force.  Nothing at first can appear
+more difficult to believe than that the more complex organs and instincts
+should have been perfected, not by means superior to, though analogous
+with, human reason, but by the accumulation of innumerable slight
+variations, each good for the individual possessor.  Nevertheless, this
+difficulty, though appearing to our imagination insuperably great, cannot
+be considered real if we admit the following propositions, namely,--that
+gradations in the perfection of any organ or instinct, which we may
+consider, either do now exist or could have existed, each good of its
+kind,--that all organs and instincts are, in ever so slight a degree,
+variable,--and, lastly, that there is a struggle for existence leading to
+the preservation of each profitable deviation of structure or instinct. 
+The truth of these propositions cannot, I think, be disputed.
+</para>
+
+<para>
+It is, no doubt, extremely difficult even to conjecture by what gradations
+many structures have been perfected, more especially amongst broken and
+failing groups of organic beings; but we see so many strange gradations in
+nature, as is proclaimed by the canon, 'Natura non facit saltum,' that we
+ought to be extremely cautious in saying that any organ or instinct, or any
+whole being, could not have arrived at its present state by many graduated
+steps.  There are, it must be admitted, cases of special difficulty on the
+theory of natural selection; and one of the most curious of these is the
+existence of two or three defined castes of workers or sterile females in
+the same community of ants; but I have attempted to show how this
+difficulty can be mastered.
+</para>
+
+<para>
+With respect to the almost universal sterility of species when first
+crossed, which forms so remarkable a contrast with the almost universal
+fertility of varieties when crossed, I must refer the reader to the
+recapitulation of the facts given at the end of the eighth chapter, which
+seem to me conclusively to show that this sterility is no more a special
+endowment than is the incapacity of two trees to be grafted together, but
+that it is incidental on constitutional differences in the reproductive
+systems of the intercrossed species.  We see the truth of this conclusion
+in the vast difference in the result, when the same two species are crossed
+reciprocally; that is, when one species is first used as the father and
+then as the mother.
+</para>
+
+<para>
+The fertility of varieties when intercrossed and of their mongrel offspring
+cannot be considered as universal; nor is their very general fertility
+surprising when we remember that it is not likely that either their
+constitutions or their reproductive systems should have been profoundly
+modified.  Moreover, most of the varieties which have been experimentised
+on have been produced under domestication; and as domestication apparently
+tends to eliminate sterility, we ought not to expect it also to produce
+sterility.
+</para>
+
+<para>
+The sterility of hybrids is a very different case from that of first
+crosses, for their reproductive organs are more or less functionally
+impotent; whereas in first crosses the organs on both sides are in a
+perfect condition.  As we continually see that organisms of all kinds are
+rendered in some degree sterile from their constitutions having been
+disturbed by slightly different and new conditions of life, we need not
+feel surprise at hybrids being in some degree sterile, for their
+constitutions can hardly fail to have been disturbed from being compounded
+of two distinct organisations.  This parallelism is supported by another
+parallel, but directly opposite, class of facts; namely, that the vigour
+and fertility of all organic beings are increased by slight changes in
+their conditions of life, and that the offspring of slightly modified forms
+or varieties acquire from being crossed increased vigour and fertility.  So
+that, on the one hand, considerable changes in the conditions of life and
+crosses between greatly modified forms, lessen fertility; and on the other
+hand, lesser changes in the conditions of life and crosses between less
+modified forms, increase fertility.
+</para>
+
+<para>
+Turning to geographical distribution, the difficulties encountered on the
+theory of descent with modification are grave enough.  All the individuals
+of the same species, and all the species of the same genus, or even higher
+group, must have descended from common parents; and therefore, in however
+distant and isolated parts of the world they are now found, they must in
+the course of successive generations have passed from some one part to the
+others.  We are often wholly unable even to conjecture how this could have
+been effected.  Yet, as we have reason to believe that some species have
+retained the same specific form for very long periods, enormously long as
+measured by years, too much stress ought not to be laid on the occasional
+wide diffusion of the same species; for during very long periods of time
+there will always be a good chance for wide migration by many means.  A
+broken or interrupted range may often be accounted for by the extinction of
+the species in the intermediate regions.  It cannot be denied that we are
+as yet very ignorant of the full extent of the various climatal and
+geographical changes which have affected the earth during modern periods;
+and such changes will obviously have greatly facilitated migration.  As an
+example, I have attempted to show how potent has been the influence of the
+Glacial period on the distribution both of the same and of representative
+species throughout the world.  We are as yet profoundly ignorant of the
+many occasional means of transport.  With respect to distinct species of
+the same genus inhabiting very distant and isolated regions, as the process
+of modification has necessarily been slow, all the means of migration will
+have been possible during a very long period; and consequently the
+difficulty of the wide diffusion of species of the same genus is in some
+degree lessened.
+</para>
+
+<para>
+As on the theory of natural selection an interminable number of
+intermediate forms must have existed, linking together all the species in
+each group by gradations as fine as our present varieties, it may be asked,
+Why do we not see these linking forms all around us?  Why are not all
+organic beings blended together in an inextricable chaos?  With respect to
+existing forms, we should remember that we have no right to expect
+(excepting in rare cases) to discover directly connecting links between
+them, but only between each and some extinct and supplanted form.  Even on
+a wide area, which has during a long period remained continuous, and of
+which the climate and other conditions of life change insensibly in going
+from a district occupied by one species into another district occupied by a
+closely allied species, we have no just right to expect often to find
+intermediate varieties in the intermediate zone.  For we have reason to
+believe that only a few species are undergoing change at any one period;
+and all changes are slowly effected.  I have also shown that the
+intermediate varieties which will at first probably exist in the
+intermediate zones, will be liable to be supplanted by the allied forms on
+either hand; and the latter, from existing in greater numbers, will
+generally be modified and improved at a quicker rate than the intermediate
+varieties, which exist in lesser numbers; so that the intermediate
+varieties will, in the long run, be supplanted and exterminated.
+</para>
+
+<para>
+On this doctrine of the extermination of an infinitude of connecting links,
+between the living and extinct inhabitants of the world, and at each
+successive period between the extinct and still older species, why is not
+every geological formation charged with such links?  Why does not every
+collection of fossil remains afford plain evidence of the gradation and
+mutation of the forms of life?  We meet with no such evidence, and this is
+the most obvious and forcible of the many objections which may be urged
+against my theory.  Why, again, do whole groups of allied species appear,
+though certainly they often falsely appear, to have come in suddenly on the
+several geological stages?  Why do we not find great piles of strata
+beneath the Silurian system, stored with the remains of the progenitors of
+the Silurian groups of fossils?  For certainly on my theory such strata
+must somewhere have been deposited at these ancient and utterly unknown
+epochs in the world's history.
+</para>
+
+<para>
+I can answer these questions and grave objections only on the supposition
+that the geological record is far more imperfect than most geologists
+believe.  It cannot be objected that there has not been time sufficient for
+any amount of organic change; for the lapse of time has been so great as to
+be utterly inappreciable by the human intellect.  The number of specimens
+in all our museums is absolutely as nothing compared with the countless
+generations of countless species which certainly have existed.  We should
+not be able to recognise a species as the parent of any one or more species
+if we were to examine them ever so closely, unless we likewise possessed
+many of the intermediate links between their past or parent and present
+states; and these many links we could hardly ever expect to discover, owing
+to the imperfection of the geological record.  Numerous existing doubtful
+forms could be named which are probably varieties; but who will pretend
+that in future ages so many fossil links will be discovered, that
+naturalists will be able to decide, on the common view, whether or not
+these doubtful forms are varieties?  As long as most of the links between
+any two species are unknown, if any one link or intermediate variety be
+discovered, it will simply be classed as another and distinct species. 
+Only a small portion of the world has been geologically explored.  Only
+organic beings of certain classes can be preserved in a fossil condition,
+at least in any great number.  Widely ranging species vary most, and
+varieties are often at first local,--both causes rendering the discovery of
+intermediate links less likely.  Local varieties will not spread into other
+and distant regions until they are considerably modified and improved; and
+when they do spread, if discovered in a geological formation, they will
+appear as if suddenly created there, and will be simply classed as new
+species.  Most formations have been intermittent in their accumulation; and
+their duration, I am inclined to believe, has been shorter than the average
+duration of specific forms.  Successive formations are separated from each
+other by enormous blank intervals of time; for fossiliferous formations,
+thick enough to resist future degradation, can be accumulated only where
+much sediment is deposited on the subsiding bed of the sea.  During the
+alternate periods of elevation and of stationary level the record will be
+blank.  During these latter periods there will probably be more variability
+in the forms of life; during periods of subsidence, more extinction.
+</para>
+
+<para>
+With respect to the absence of fossiliferous formations beneath the lowest
+Silurian strata, I can only recur to the hypothesis given in the ninth
+chapter.  That the geological record is imperfect all will admit; but that
+it is imperfect to the degree which I require, few will be inclined to
+admit.  If we look to long enough intervals of time, geology plainly
+declares that all species have changed; and they have changed in the manner
+which my theory requires, for they have changed slowly and in a graduated
+manner.  We clearly see this in the fossil remains from consecutive
+formations invariably being much more closely related to each other, than
+are the fossils from formations distant from each other in time.
+</para>
+
+<para>
+Such is the sum of the several chief objections and difficulties which may
+justly be urged against my theory; and I have now briefly recapitulated the
+answers and explanations which can be given to them.  I have felt these
+difficulties far too heavily during many years to doubt their weight.  But
+it deserves especial notice that the more important objections relate to
+questions on which we are confessedly ignorant; nor do we know how ignorant
+we are.  We do not know all the possible transitional gradations between
+the simplest and the most perfect organs; it cannot be pretended that we
+know all the varied means of Distribution during the long lapse of years,
+or that we know how imperfect the Geological Record is.  Grave as these
+several difficulties are, in my judgment they do not overthrow the theory
+of descent with modification.
+</para>
+
+<para>
+Now let us turn to the other side of the argument.  Under domestication we
+see much variability.  This seems to be mainly due to the reproductive
+system being eminently susceptible to changes in the conditions of life; so
+that this system, when not rendered impotent, fails to reproduce offspring
+exactly like the parent-form.  Variability is governed by many complex
+laws,--by correlation of growth, by use and disuse, and by the direct
+action of the physical conditions of life.  There is much difficulty in
+ascertaining how much modification our domestic productions have undergone;
+but we may safely infer that the amount has been large, and that
+modifications can be inherited for long periods.  As long as the conditions
+of life remain the same, we have reason to believe that a modification,
+which has already been inherited for many generations, may continue to be
+inherited for an almost infinite number of generations.  On the other hand
+we have evidence that variability, when it has once come into play, does
+not wholly cease; for new varieties are still occasionally produced by our
+most anciently domesticated productions.
+</para>
+
+<para>
+Man does not actually produce variability; he only unintentionally exposes
+organic beings to new conditions of life, and then nature acts on the
+organisation, and causes variability.  But man can and does select the
+variations given to him by nature, and thus accumulate them in any desired
+manner.  He thus adapts animals and plants for his own benefit or pleasure. 
+He may do this methodically, or he may do it unconsciously by preserving
+the individuals most useful to him at the time, without any thought of
+altering the breed.  It is certain that he can largely influence the
+character of a breed by selecting, in each successive generation,
+individual differences so slight as to be quite inappreciable by an
+uneducated eye.  This process of selection has been the great agency in the
+production of the most distinct and useful domestic breeds.  That many of
+the breeds produced by man have to a large extent the character of natural
+species, is shown by the inextricable doubts whether very many of them are
+varieties or aboriginal species.
+</para>
+
+<para>
+There is no obvious reason why the principles which have acted so
+efficiently under domestication should not have acted under nature.  In the
+preservation of favoured individuals and races, during the
+constantly-recurrent Struggle for Existence, we see the most powerful and
+ever-acting means of selection.  The struggle for existence inevitably
+follows from the high geometrical ratio of increase which is common to all
+organic beings.  This high rate of increase is proved by calculation, by
+the effects of a succession of peculiar seasons, and by the results of
+naturalisation, as explained in the third chapter.  More individuals are
+born than can possibly survive.  A grain in the balance will determine
+which individual shall live and which shall die,--which variety or species
+shall increase in number, and which shall decrease, or finally become
+extinct.  As the individuals of the same species come in all respects into
+the closest competition with each other, the struggle will generally be
+most severe between them; it will be almost equally severe between the
+varieties of the same species, and next in severity between the species of
+the same genus.  But the struggle will often be very severe between beings
+most remote in the scale of nature.  The slightest advantage in one being,
+at any age or during any season, over those with which it comes into
+competition, or better adaptation in however slight a degree to the
+surrounding physical conditions, will turn the balance.
+</para>
+
+<para>
+With animals having separated sexes there will in most cases be a struggle
+between the males for possession of the females.  The most vigorous
+individuals, or those which have most successfully struggled with their
+conditions of life, will generally leave most progeny.  But success will
+often depend on having special weapons or means of defence, or on the
+charms of the males; and the slightest advantage will lead to victory.
+</para>
+
+<para>
+As geology plainly proclaims that each land has undergone great physical
+changes, we might have expected that organic beings would have varied under
+nature, in the same way as they generally have varied under the changed
+conditions of domestication.  And if there be any variability under nature,
+it would be an unaccountable fact if natural selection had not come into
+play.  It has often been asserted, but the assertion is quite incapable of
+proof, that the amount of variation under nature is a strictly limited
+quantity.  Man, though acting on external characters alone and often
+capriciously, can produce within a short period a great result by adding up
+mere individual differences in his domestic productions; and every one
+admits that there are at least individual differences in species under
+nature.  But, besides such differences, all naturalists have admitted the
+existence of varieties, which they think sufficiently distinct to be worthy
+of record in systematic works.  No one can draw any clear distinction
+between individual differences and slight varieties; or between more
+plainly marked varieties and sub-species, and species.  Let it be observed
+how naturalists differ in the rank which they assign to the many
+representative forms in Europe and North America.
+</para>
+
+<para>
+If then we have under nature variability and a powerful agent always ready
+to act and select, why should we doubt that variations in any way useful to
+beings, under their excessively complex relations of life, would be
+preserved, accumulated, and inherited?  Why, if man can by patience select
+variations most useful to himself, should nature fail in selecting
+variations useful, under changing conditions of life, to her living
+products?  What limit can be put to this power, acting during long ages and
+rigidly scrutinising the whole constitution, structure, and habits of each
+creature,--favouring the good and rejecting the bad?  I can see no limit to
+this power, in slowly and beautifully adapting each form to the most
+complex relations of life.  The theory of natural selection, even if we
+looked no further than this, seems to me to be in itself probable.  I have
+already recapitulated, as fairly as I could, the opposed difficulties and
+objections:  now let us turn to the special facts and arguments in favour
+of the theory.
+</para>
+
+<para>
+On the view that species are only strongly marked and permanent varieties,
+and that each species first existed as a variety, we can see why it is that
+no line of demarcation can be drawn between species, commonly supposed to
+have been produced by special acts of creation, and varieties which are
+acknowledged to have been produced by secondary laws.  On this same view we
+can understand how it is that in each region where many species of a genus
+have been produced, and where they now flourish, these same species should
+present many varieties; for where the manufactory of species has been
+active, we might expect, as a general rule, to find it still in action; and
+this is the case if varieties be incipient species.  Moreover, the species
+of the large genera, which afford the greater number of varieties or
+incipient species, retain to a certain degree the character of varieties;
+for they differ from each other by a less amount of difference than do the
+species of smaller genera.  The closely allied species also of the larger
+genera apparently have restricted ranges, and they are clustered in little
+groups round other species--in which respects they resemble varieties. 
+These are strange relations on the view of each species having been
+independently created, but are intelligible if all species first existed as
+varieties.
+</para>
+
+<para>
+As each species tends by its geometrical ratio of reproduction to increase
+inordinately in number; and as the modified descendants of each species
+will be enabled to increase by so much the more as they become more
+diversified in habits and structure, so as to be enabled to seize on many
+and widely different places in the economy of nature, there will be a
+constant tendency in natural selection to preserve the most divergent
+offspring of any one species.  Hence during a long-continued course of
+modification, the slight differences, characteristic of varieties of the
+same species, tend to be augmented into the greater differences
+characteristic of species of the same genus.  New and improved varieties
+will inevitably supplant and exterminate the older, less improved and
+intermediate varieties; and thus species are rendered to a large extent
+defined and distinct objects.  Dominant species belonging to the larger
+groups tend to give birth to new and dominant forms; so that each large
+group tends to become still larger, and at the same time more divergent in
+character.  But as all groups cannot thus succeed in increasing in size,
+for the world would not hold them, the more dominant groups beat the less
+dominant.  This tendency in the large groups to go on increasing in size
+and diverging in character, together with the almost inevitable contingency
+of much extinction, explains the arrangement of all the forms of life, in
+groups subordinate to groups, all within a few great classes, which we now
+see everywhere around us, and which has prevailed throughout all time. 
+This grand fact of the grouping of all organic beings seems to me utterly
+inexplicable on the theory of creation.
+</para>
+
+<para>
+As natural selection acts solely by accumulating slight, successive,
+favourable variations, it can produce no great or sudden modification; it
+can act only by very short and slow steps.  Hence the canon of 'Natura non
+facit saltum,' which every fresh addition to our knowledge tends to make
+more strictly correct, is on this theory simply intelligible.  We can
+plainly see why nature is prodigal in variety, though niggard in
+innovation.  But why this should be a law of nature if each species has
+been independently created, no man can explain.
+</para>
+
+<para>
+Many other facts are, as it seems to me, explicable on this theory.  How
+strange it is that a bird, under the form of woodpecker, should have been
+created to prey on insects on the ground; that upland geese, which never or
+rarely swim, should have been created with webbed feet; that a thrush
+should have been created to dive and feed on sub-aquatic insects; and that
+a petrel should have been created with habits and structure fitting it for
+the life of an auk or grebe! and so on in endless other cases.  But on the
+view of each species constantly trying to increase in number, with natural
+selection always ready to adapt the slowly varying descendants of each to
+any unoccupied or ill-occupied place in nature, these facts cease to be
+strange, or perhaps might even have been anticipated.
+</para>
+
+<para>
+As natural selection acts by competition, it adapts the inhabitants of each
+country only in relation to the degree of perfection of their associates;
+so that we need feel no surprise at the inhabitants of any one country,
+although on the ordinary view supposed to have been specially created and
+adapted for that country, being beaten and supplanted by the naturalised
+productions from another land.  Nor ought we to marvel if all the
+contrivances in nature be not, as far as we can judge, absolutely perfect;
+and if some of them be abhorrent to our ideas of fitness.  We need not
+marvel at the sting of the bee causing the bee's own death; at drones being
+produced in such vast numbers for one single act, and being then
+slaughtered by their sterile sisters; at the astonishing waste of pollen by
+our fir-trees; at the instinctive hatred of the queen bee for her own
+fertile daughters; at ichneumonidae feeding within the live bodies of
+caterpillars; and at other such cases.  The wonder indeed is, on the theory
+of natural selection, that more cases of the want of absolute perfection
+have not been observed.
+</para>
+
+<para>
+The complex and little known laws governing variation are the same, as far
+as we can see, with the laws which have governed the production of
+so-called specific forms.  In both cases physical conditions seem to have
+produced but little direct effect; yet when varieties enter any zone, they
+occasionally assume some of the characters of the species proper to that
+zone.  In both varieties and species, use and disuse seem to have produced
+some effect; for it is difficult to resist this conclusion when we look,
+for instance, at the logger-headed duck, which has wings incapable of
+flight, in nearly the same condition as in the domestic duck; or when we
+look at the burrowing tucutucu, which is occasionally blind, and then at
+certain moles, which are habitually blind and have their eyes covered with
+skin; or when we look at the blind animals inhabiting the dark caves of
+America and Europe.  In both varieties and species correlation of growth
+seems to have played a most important part, so that when one part has been
+modified other parts are necessarily modified.  In both varieties and
+species reversions to long-lost characters occur.  How inexplicable on the
+theory of creation is the occasional appearance of stripes on the shoulder
+and legs of the several species of the horse-genus and in their hybrids! 
+How simply is this fact explained if we believe that these species have
+descended from a striped progenitor, in the same manner as the several
+domestic breeds of pigeon have descended from the blue and barred
+rock-pigeon!
+</para>
+
+<para>
+On the ordinary view of each species having been independently created, why
+should the specific characters, or those by which the species of the same
+genus differ from each other, be more variable than the generic characters
+in which they all agree?  Why, for instance, should the colour of a flower
+be more likely to vary in any one species of a genus, if the other species,
+supposed to have been created independently, have differently coloured
+flowers, than if all the species of the genus have the same coloured
+flowers?  If species are only well-marked varieties, of which the
+characters have become in a high degree permanent, we can understand this
+fact; for they have already varied since they branched off from a common
+progenitor in certain characters, by which they have come to be
+specifically distinct from each other; and therefore these same characters
+would be more likely still to be variable than the generic characters which
+have been inherited without change for an enormous period.  It is
+inexplicable on the theory of creation why a part developed in a very
+unusual manner in any one species of a genus, and therefore, as we may
+naturally infer, of great importance to the species, should be eminently
+liable to variation; but, on my view, this part has undergone, since the
+several species branched off from a common progenitor, an unusual amount of
+variability and modification, and therefore we might expect this part
+generally to be still variable.  But a part may be developed in the most
+unusual manner, like the wing of a bat, and yet not be more variable than
+any other structure, if the part be common to many subordinate forms, that
+is, if it has been inherited for a very long period; for in this case it
+will have been rendered constant by long-continued natural selection.
+</para>
+
+<para>
+Glancing at instincts, marvellous as some are, they offer no greater
+difficulty than does corporeal structure on the theory of the natural
+selection of successive, slight, but profitable modifications.  We can thus
+understand why nature moves by graduated steps in endowing different
+animals of the same class with their several instincts.  I have attempted
+to show how much light the principle of gradation throws on the admirable
+architectural powers of the hive-bee.  Habit no doubt sometimes comes into
+play in modifying instincts; but it certainly is not indispensable, as we
+see, in the case of neuter insects, which leave no progeny to inherit the
+effects of long-continued habit.  On the view of all the species of the
+same genus having descended from a common parent, and having inherited much
+in common, we can understand how it is that allied species, when placed
+under considerably different conditions of life, yet should follow nearly
+the same instincts; why the thrush of South America, for instance, lines
+her nest with mud like our British species.  On the view of instincts
+having been slowly acquired through natural selection we need not marvel at
+some instincts being apparently not perfect and liable to mistakes, and at
+many instincts causing other animals to suffer.
+</para>
+
+<para>
+If species be only well-marked and permanent varieties, we can at once see
+why their crossed offspring should follow the same complex laws in their
+degrees and kinds of resemblance to their parents,--in being absorbed into
+each other by successive crosses, and in other such points,--as do the
+crossed offspring of acknowledged varieties.  On the other hand, these
+would be strange facts if species have been independently created, and
+varieties have been produced by secondary laws.
+</para>
+
+<para>
+If we admit that the geological record is imperfect in an extreme degree,
+then such facts as the record gives, support the theory of descent with
+modification.  New species have come on the stage slowly and at successive
+intervals; and the amount of change, after equal intervals of time, is
+widely different in different groups.  The extinction of species and of
+whole groups of species, which has played so conspicuous a part in the
+history of the organic world, almost inevitably follows on the principle of
+natural selection; for old forms will be supplanted by new and improved
+forms.  Neither single species nor groups of species reappear when the
+chain of ordinary generation has once been broken.  The gradual diffusion
+of dominant forms, with the slow modification of their descendants, causes
+the forms of life, after long intervals of time, to appear as if they had
+changed simultaneously throughout the world.  The fact of the fossil
+remains of each formation being in some degree intermediate in character
+between the fossils in the formations above and below, is simply explained
+by their intermediate position in the chain of descent.  The grand fact
+that all extinct organic beings belong to the same system with recent
+beings, falling either into the same or into intermediate groups, follows
+from the living and the extinct being the offspring of common parents.  As
+the groups which have descended from an ancient progenitor have generally
+diverged in character, the progenitor with its early descendants will often
+be intermediate in character in comparison with its later descendants; and
+thus we can see why the more ancient a fossil is, the oftener it stands in
+some degree intermediate between existing and allied groups.  Recent forms
+are generally looked at as being, in some vague sense, higher than ancient
+and extinct forms; and they are in so far higher as the later and more
+improved forms have conquered the older and less improved organic beings in
+the struggle for life.  Lastly, the law of the long endurance of allied
+forms on the same continent,--of marsupials in Australia, of edentata in
+America, and other such cases,--is intelligible, for within a confined
+country, the recent and the extinct will naturally be allied by descent.
+</para>
+
+<para>
+Looking to geographical distribution, if we admit that there has been
+during the long course of ages much migration from one part of the world to
+another, owing to former climatal and geographical changes and to the many
+occasional and unknown means of dispersal, then we can understand, on the
+theory of descent with modification, most of the great leading facts in
+Distribution.  We can see why there should be so striking a parallelism in
+the distribution of organic beings throughout space, and in their
+geological succession throughout time; for in both cases the beings have
+been connected by the bond of ordinary generation, and the means of
+modification have been the same.  We see the full meaning of the wonderful
+fact, which must have struck every traveller, namely, that on the same
+continent, under the most diverse conditions, under heat and cold, on
+mountain and lowland, on deserts and marshes, most of the inhabitants
+within each great class are plainly related; for they will generally be
+descendants of the same progenitors and early colonists.  On this same
+principle of former migration, combined in most cases with modification, we
+can understand, by the aid of the Glacial period, the identity of some few
+plants, and the close alliance of many others, on the most distant
+mountains, under the most different climates; and likewise the close
+alliance of some of the inhabitants of the sea in the northern and southern
+temperate zones, though separated by the whole intertropical ocean. 
+Although two areas may present the same physical conditions of life, we
+need feel no surprise at their inhabitants being widely different, if they
+have been for a long period completely separated from each other; for as
+the relation of organism to organism is the most important of all
+relations, and as the two areas will have received colonists from some
+third source or from each other, at various periods and in different
+proportions, the course of modification in the two areas will inevitably be
+different.
+</para>
+
+<para>
+On this view of migration, with subsequent modification, we can see why
+oceanic islands should be inhabited by few species, but of these, that many
+should be peculiar.  We can clearly see why those animals which cannot
+cross wide spaces of ocean, as frogs and terrestrial mammals, should not
+inhabit oceanic islands; and why, on the other hand, new and peculiar
+species of bats, which can traverse the ocean, should so often be found on
+islands far distant from any continent.  Such facts as the presence of
+peculiar species of bats, and the absence of all other mammals, on oceanic
+islands, are utterly inexplicable on the theory of independent acts of
+creation.
+</para>
+
+<para>
+The existence of closely allied or representative species in any two areas,
+implies, on the theory of descent with modification, that the same parents
+formerly inhabited both areas; and we almost invariably find that wherever
+many closely allied species inhabit two areas, some identical species
+common to both still exist.  Wherever many closely allied yet distinct
+species occur, many doubtful forms and varieties of the same species
+likewise occur.  It is a rule of high generality that the inhabitants of
+each area are related to the inhabitants of the nearest source whence
+immigrants might have been derived.  We see this in nearly all the plants
+and animals of the Galapagos archipelago, of Juan Fernandez, and of the
+other American islands being related in the most striking manner to the
+plants and animals of the neighbouring American mainland; and those of the
+Cape de Verde archipelago and other African islands to the African
+mainland.  It must be admitted that these facts receive no explanation on
+the theory of creation.
+</para>
+
+<para>
+The fact, as we have seen, that all past and present organic beings
+constitute one grand natural system, with group subordinate to group, and
+with extinct groups often falling in between recent groups, is intelligible
+on the theory of natural selection with its contingencies of extinction and
+divergence of character.  On these same principles we see how it is, that
+the mutual affinities of the species and genera within each class are so
+complex and circuitous.  We see why certain characters are far more
+serviceable than others for classification;--why adaptive characters,
+though of paramount importance to the being, are of hardly any importance
+in classification; why characters derived from rudimentary parts, though of
+no service to the being, are often of high classificatory value; and why
+embryological characters are the most valuable of all.  The real affinities
+of all organic beings are due to inheritance or community of descent.  The
+natural system is a genealogical arrangement, in which we have to discover
+the lines of descent by the most permanent characters, however slight their
+vital importance may be.
+</para>
+
+<para>
+The framework of bones being the same in the hand of a man, wing of a bat,
+fin of the porpoise, and leg of the horse,--the same number of vertebrae
+forming the neck of the giraffe and of the elephant,--and innumerable other
+such facts, at once explain themselves on the theory of descent with slow
+and slight successive modifications.  The similarity of pattern in the wing
+and leg of a bat, though used for such different purpose,--in the jaws and
+legs of a crab,--in the petals, stamens, and pistils of a flower, is
+likewise intelligible on the view of the gradual modification of parts or
+organs, which were alike in the early progenitor of each class.  On the
+principle of successive variations not always supervening at an early age,
+and being inherited at a corresponding not early period of life, we can
+clearly see why the embryos of mammals, birds, reptiles, and fishes should
+be so closely alike, and should be so unlike the adult forms.  We may cease
+marvelling at the embryo of an air-breathing mammal or bird having
+branchial slits and arteries running in loops, like those in a fish which
+has to breathe the air dissolved in water, by the aid of well-developed
+branchiae.
+</para>
+
+<para>
+Disuse, aided sometimes by natural selection, will often tend to reduce an
+organ, when it has become useless by changed habits or under changed
+conditions of life; and we can clearly understand on this view the meaning
+of rudimentary organs.  But disuse and selection will generally act on each
+creature, when it has come to maturity and has to play its full part in the
+struggle for existence, and will thus have little power of acting on an
+organ during early life; hence the organ will not be much reduced or
+rendered rudimentary at this early age.  The calf, for instance, has
+inherited teeth, which never cut through the gums of the upper jaw, from an
+early progenitor having well-developed teeth; and we may believe, that the
+teeth in the mature animal were reduced, during successive generations, by
+disuse or by the tongue and palate having been fitted by natural selection
+to browse without their aid; whereas in the calf, the teeth have been left
+untouched by selection or disuse, and on the principle of inheritance at
+corresponding ages have been inherited from a remote period to the present
+day.  On the view of each organic being and each separate organ having been
+specially created, how utterly inexplicable it is that parts, like the
+teeth in the embryonic calf or like the shrivelled wings under the soldered
+wing-covers of some beetles, should thus so frequently bear the plain stamp
+of inutility!  Nature may be said to have taken pains to reveal, by
+rudimentary organs and by homologous structures, her scheme of
+modification, which it seems that we wilfully will not understand.
+</para>
+
+<para>
+I have now recapitulated the chief facts and considerations which have
+thoroughly convinced me that species have changed, and are still slowly
+changing by the preservation and accumulation of successive slight
+favourable variations.  Why, it may be asked, have all the most eminent
+living naturalists and geologists rejected this view of the mutability of
+species?  It cannot be asserted that organic beings in a state of nature
+are subject to no variation; it cannot be proved that the amount of
+variation in the course of long ages is a limited quantity; no clear
+distinction has been, or can be, drawn between species and well-marked
+varieties.  It cannot be maintained that species when intercrossed are
+invariably sterile, and varieties invariably fertile; or that sterility is
+a special endowment and sign of creation.  The belief that species were
+immutable productions was almost unavoidable as long as the history of the
+world was thought to be of short duration; and now that we have acquired
+some idea of the lapse of time, we are too apt to assume, without proof,
+that the geological record is so perfect that it would have afforded us
+plain evidence of the mutation of species, if they had undergone mutation.
+</para>
+
+<para>
+But the chief cause of our natural unwillingness to admit that one species
+has given birth to other and distinct species, is that we are always slow
+in admitting any great change of which we do not see the intermediate
+steps.  The difficulty is the same as that felt by so many geologists, when
+Lyell first insisted that long lines of inland cliffs had been formed, and
+great valleys excavated, by the slow action of the coast-waves.  The mind
+cannot possibly grasp the full meaning of the term of a hundred million
+years; it cannot add up and perceive the full effects of many slight
+variations, accumulated during an almost infinite number of generations.
+</para>
+
+<para>
+Although I am fully convinced of the truth of the views given in this
+volume under the form of an abstract, I by no means expect to convince
+experienced naturalists whose minds are stocked with a multitude of facts
+all viewed, during a long course of years, from a point of view directly
+opposite to mine.  It is so easy to hide our ignorance under such
+expressions as the 'plan of creation,' 'unity of design,' &amp;c., and to think
+that we give an explanation when we only restate a fact.  Any one whose
+disposition leads him to attach more weight to unexplained difficulties
+than to the explanation of a certain number of facts will certainly reject
+my theory.  A few naturalists, endowed with much flexibility of mind, and
+who have already begun to doubt on the immutability of species, may be
+influenced by this volume; but I look with confidence to the future, to
+young and rising naturalists, who will be able to view both sides of the
+question with impartiality.  Whoever is led to believe that species are
+mutable will do good service by conscientiously expressing his conviction;
+for only thus can the load of prejudice by which this subject is
+overwhelmed be removed.
+</para>
+
+<para>
+Several eminent naturalists have of late published their belief that a
+multitude of reputed species in each genus are not real species; but that
+other species are real, that is, have been independently created.  This
+seems to me a strange conclusion to arrive at.  They admit that a multitude
+of forms, which till lately they themselves thought were special creations,
+and which are still thus looked at by the majority of naturalists, and
+which consequently have every external characteristic feature of true
+species,--they admit that these have been produced by variation, but they
+refuse to extend the same view to other and very slightly different forms. 
+Nevertheless they do not pretend that they can define, or even conjecture,
+which are the created forms of life, and which are those produced by
+secondary laws.  They admit variation as a vera causa in one case, they
+arbitrarily reject it in another, without assigning any distinction in the
+two cases.  The day will come when this will be given as a curious
+illustration of the blindness of preconceived opinion.  These authors seem
+no more startled at a miraculous act of creation than at an ordinary birth. 
+But do they really believe that at innumerable periods in the earth's
+history certain elemental atoms have been commanded suddenly to flash into
+living tissues?  Do they believe that at each supposed act of creation one
+individual or many were produced?  Were all the infinitely numerous kinds
+of animals and plants created as eggs or seed, or as full grown? and in the
+case of mammals, were they created bearing the false marks of nourishment
+from the mother's womb?  Although naturalists very properly demand a full
+explanation of every difficulty from those who believe in the mutability of
+species, on their own side they ignore the whole subject of the first
+appearance of species in what they consider reverent silence.
+</para>
+
+<para>
+It may be asked how far I extend the doctrine of the modification of
+species.  The question is difficult to answer, because the more distinct
+the forms are which we may consider, by so much the arguments fall away in
+force.  But some arguments of the greatest weight extend very far.  All the
+members of whole classes can be connected together by chains of affinities,
+and all can be classified on the same principle, in groups subordinate to
+groups.  Fossil remains sometimes tend to fill up very wide intervals
+between existing orders.  Organs in a rudimentary condition plainly show
+that an early progenitor had the organ in a fully developed state; and this
+in some instances necessarily implies an enormous amount of modification in
+the descendants.  Throughout whole classes various structures are formed on
+the same pattern, and at an embryonic age the species closely resemble each
+other.  Therefore I cannot doubt that the theory of descent with
+modification embraces all the members of the same class.  I believe that
+animals have descended from at most only four or five progenitors, and
+plants from an equal or lesser number.
+</para>
+
+<para>
+Analogy would lead me one step further, namely, to the belief that all
+animals and plants have descended from some one prototype.  But analogy may
+be a deceitful guide.  Nevertheless all living things have much in common,
+in their chemical composition, their germinal vesicles, their cellular
+structure, and their laws of growth and reproduction.  We see this even in
+so trifling a circumstance as that the same poison often similarly affects
+plants and animals; or that the poison secreted by the gall-fly produces
+monstrous growths on the wild rose or oak-tree.  Therefore I should infer
+from analogy that probably all the organic beings which have ever lived on
+this earth have descended from some one primordial form, into which life
+was first breathed.
+</para>
+
+<para>
+When the views entertained in this volume on the origin of species, or when
+analogous views are generally admitted, we can dimly foresee that there
+will be a considerable revolution in natural history.  Systematists will be
+able to pursue their labours as at present; but they will not be
+incessantly haunted by the shadowy doubt whether this or that form be in
+essence a species.  This I feel sure, and I speak after experience, will be
+no slight relief.  The endless disputes whether or not some fifty species
+of British brambles are true species will cease.  Systematists will have
+only to decide (not that this will be easy) whether any form be
+sufficiently constant and distinct from other forms, to be capable of
+definition; and if definable, whether the differences be sufficiently
+important to deserve a specific name.  This latter point will become a far
+more essential consideration than it is at present; for differences,
+however slight, between any two forms, if not blended by intermediate
+gradations, are looked at by most naturalists as sufficient to raise both
+forms to the rank of species.  Hereafter we shall be compelled to
+acknowledge that the only distinction between species and well-marked
+varieties is, that the latter are known, or believed, to be connected at
+the present day by intermediate gradations, whereas species were formerly
+thus connected.  Hence, without quite rejecting the consideration of the
+present existence of intermediate gradations between any two forms, we
+shall be led to weigh more carefully and to value higher the actual amount
+of difference between them.  It is quite possible that forms now generally
+acknowledged to be merely varieties may hereafter be thought worthy of
+specific names, as with the primrose and cowslip; and in this case
+scientific and common language will come into accordance.  In short, we
+shall have to treat species in the same manner as those naturalists treat
+genera, who admit that genera are merely artificial combinations made for
+convenience.  This may not be a cheering prospect; but we shall at least be
+freed from the vain search for the undiscovered and undiscoverable essence
+of the term species.
+</para>
+
+<para>
+The other and more general departments of natural history will rise greatly
+in interest.  The terms used by naturalists of affinity, relationship,
+community of type, paternity, morphology, adaptive characters, rudimentary
+and aborted organs, &amp;c., will cease to be metaphorical, and will have a
+plain signification.  When we no longer look at an organic being as a
+savage looks at a ship, as at something wholly beyond his comprehension;
+when we regard every production of nature as one which has had a history;
+when we contemplate every complex structure and instinct as the summing up
+of many contrivances, each useful to the possessor, nearly in the same way
+as when we look at any great mechanical invention as the summing up of the
+labour, the experience, the reason, and even the blunders of numerous
+workmen; when we thus view each organic being, how far more interesting, I
+speak from experience, will the study of natural history become!
+</para>
+
+<para>
+A grand and almost untrodden field of inquiry will be opened, on the causes
+and laws of variation, on correlation of growth, on the effects of use and
+disuse, on the direct action of external conditions, and so forth.  The
+study of domestic productions will rise immensely in value.  A new variety
+raised by man will be a far more important and interesting subject for
+study than one more species added to the infinitude of already recorded
+species.  Our classifications will come to be, as far as they can be so
+made, genealogies; and will then truly give what may be called the plan of
+creation.  The rules for classifying will no doubt become simpler when we
+have a definite object in view.  We possess no pedigrees or armorial
+bearings; and we have to discover and trace the many diverging lines of
+descent in our natural genealogies, by characters of any kind which have
+long been inherited.  Rudimentary organs will speak infallibly with respect
+to the nature of long-lost structures.  Species and groups of species,
+which are called aberrant, and which may fancifully be called living
+fossils, will aid us in forming a picture of the ancient forms of life. 
+Embryology will reveal to us the structure, in some degree obscured, of the
+prototypes of each great class.
+</para>
+
+<para>
+When we can feel assured that all the individuals of the same species, and
+all the closely allied species of most genera, have within a not very
+remote period descended from one parent, and have migrated from some one
+birthplace; and when we better know the many means of migration, then, by
+the light which geology now throws, and will continue to throw, on former
+changes of climate and of the level of the land, we shall surely be enabled
+to trace in an admirable manner the former migrations of the inhabitants of
+the whole world.  Even at present, by comparing the differences of the
+inhabitants of the sea on the opposite sides of a continent, and the nature
+of the various inhabitants of that continent in relation to their apparent
+means of immigration, some light can be thrown on ancient geography.
+</para>
+
+<para>
+The noble science of Geology loses glory from the extreme imperfection of
+the record.  The crust of the earth with its embedded remains must not be
+looked at as a well-filled museum, but as a poor collection made at hazard
+and at rare intervals.  The accumulation of each great fossiliferous
+formation will be recognised as having depended on an unusual concurrence
+of circumstances, and the blank intervals between the successive stages as
+having been of vast duration.  But we shall be able to gauge with some
+security the duration of these intervals by a comparison of the preceding
+and succeeding organic forms.  We must be cautious in attempting to
+correlate as strictly contemporaneous two formations, which include few
+identical species, by the general succession of their forms of life.  As
+species are produced and exterminated by slowly acting and still existing
+causes, and not by miraculous acts of creation and by catastrophes; and as
+the most important of all causes of organic change is one which is almost
+independent of altered and perhaps suddenly altered physical conditions,
+namely, the mutual relation of organism to organism,--the improvement of
+one being entailing the improvement or the extermination of others; it
+follows, that the amount of organic change in the fossils of consecutive
+formations probably serves as a fair measure of the lapse of actual time. 
+A number of species, however, keeping in a body might remain for a long
+period unchanged, whilst within this same period, several of these species,
+by migrating into new countries and coming into competition with foreign
+associates, might become modified; so that we must not overrate the
+accuracy of organic change as a measure of time.  During early periods of
+the earth's history, when the forms of life were probably fewer and
+simpler, the rate of change was probably slower; and at the first dawn of
+life, when very few forms of the simplest structure existed, the rate of
+change may have been slow in an extreme degree.  The whole history of the
+world, as at present known, although of a length quite incomprehensible by
+us, will hereafter be recognised as a mere fragment of time, compared with
+the ages which have elapsed since the first creature, the progenitor of
+innumerable extinct and living descendants, was created.
+</para>
+
+<para>
+In the distant future I see open fields for far more important researches. 
+Psychology will be based on a new foundation, that of the necessary
+acquirement of each mental power and capacity by gradation.  Light will be
+thrown on the origin of man and his history.
+</para>
+
+<para>
+Authors of the highest eminence seem to be fully satisfied with the view
+that each species has been independently created.  To my mind it accords
+better with what we know of the laws impressed on matter by the Creator,
+that the production and extinction of the past and present inhabitants of
+the world should have been due to secondary causes, like those determining
+the birth and death of the individual.  When I view all beings not as
+special creations, but as the lineal descendants of some few beings which
+lived long before the first bed of the Silurian system was deposited, they
+seem to me to become ennobled.  Judging from the past, we may safely infer
+that not one living species will transmit its unaltered likeness to a
+distant futurity.  And of the species now living very few will transmit
+progeny of any kind to a far distant futurity; for the manner in which all
+organic beings are grouped, shows that the greater number of species of
+each genus, and all the species of many genera, have left no descendants,
+but have become utterly extinct.  We can so far take a prophetic glance
+into futurity as to foretel that it will be the common and widely-spread
+species, belonging to the larger and dominant groups, which will ultimately
+prevail and procreate new and dominant species.  As all the living forms of
+life are the lineal descendants of those which lived long before the
+Silurian epoch, we may feel certain that the ordinary succession by
+generation has never once been broken, and that no cataclysm has desolated
+the whole world.  Hence we may look with some confidence to a secure future
+of equally inappreciable length.  And as natural selection works solely by
+and for the good of each being, all corporeal and mental endowments will
+tend to progress towards perfection.
+</para>
+
+<para>
+It is interesting to contemplate an entangled bank, clothed with many
+plants of many kinds, with birds singing on the bushes, with various
+insects flitting about, and with worms crawling through the damp earth, and
+to reflect that these elaborately constructed forms, so different from each
+other, and dependent on each other in so complex a manner, have all been
+produced by laws acting around us.  These laws, taken in the largest sense,
+being Growth with Reproduction; Inheritance which is almost implied by
+reproduction; Variability from the indirect and direct action of the
+external conditions of life, and from use and disuse; a Ratio of Increase
+so high as to lead to a Struggle for Life, and as a consequence to Natural
+Selection, entailing Divergence of Character and the Extinction of
+less-improved forms.  Thus, from the war of nature, from famine and death,
+the most exalted object which we are capable of conceiving, namely, the
+production of the higher animals, directly follows.  There is grandeur in
+this view of life, with its several powers, having been originally breathed
+into a few forms or into one; and that, whilst this planet has gone cycling
+on according to the fixed law of gravity, from so simple a beginning
+endless forms most beautiful and most wonderful have been, and are being,
+evolved.
+</para>
+</chapter>
+</bookbody>
+<backmatter>
+
+<index>
+
+<title>
+Subject Index
+</title>
+
+<item>
+Aberrant groups
+</item>
+
+<item>
+Abyssinia, plants of
+</item>
+
+<item>
+Acclimatisation
+</item>
+
+<item>
+Affinities of extinct species; of organic beings
+</item>
+
+<item>
+Agassiz on Amblyopsis; on groups of species suddenly appearing; on
+embryological succession; on the glacial period; on embryological
+characters; on the embryos of vertebrata; on parallelism of embryological
+development and geological succession
+</item>
+<item>
+Algae of New Zealand
+</item>
+
+<item>
+Alligators, males, fighting
+</item>
+
+<item>
+Amblyopsis, blind fish
+</item>
+
+<item>
+America, North, productions allied to those of Europe; boulders and
+glaciers of; South, no modern formations on west coast
+</item>
+
+<item>
+Ammonites, sudden extinction of
+</item>
+
+<item>
+Anagallis, sterility of
+</item>
+
+<item>
+Analog of variations
+</item>
+
+<item>
+Ancylus
+</item>
+
+<item>
+Animals, not domesticated from being variable; domestic; descended from
+several stocks; acclimatisation of; of Australia; with thicker fur in cold
+climates; blind, in caves; extinct, of Australia
+</item>
+
+<item>
+Anomma
+</item>
+
+<item>
+Antarctic islands, ancient flora of
+</item>
+
+<item>
+Antirrhinum
+</item>
+
+<item>
+Ants attending aphides; slave-making instinct
+</item>
+
+<item>
+Ants, neuter, structure of
+</item>
+
+<item>
+Aphides attended by ants
+</item>
+
+<item>
+Aphis, development of
+</item>
+
+<item>
+Apteryx
+</item>
+
+<item>
+Arab horses
+</item>
+
+<item>
+Aralo-Caspian Sea
+</item>
+
+<item>
+Archiac, M. de, on the succession of species
+</item>
+
+<item>
+Artichoke, Jerusalem
+</item>
+
+<item>
+Ascension, plants of
+</item>
+
+<item>
+Asclepias, pollen of
+</item>
+
+<item>
+Asparagus
+</item>
+
+<item>
+Aspicarpa
+</item>
+
+<item>
+Asses, striped
+</item>
+
+<item>
+Ateuchus
+</item>
+
+<item>
+Audubon, on habits of frigate-bird; on variation in birds'-nests; on heron
+eating seeds
+</item>
+
+<item>
+Australia, animals of; dogs of; extinct animals of; European plants in
+</item>
+
+<item>
+Azara on flies destroying cattle
+</item>
+
+<item>
+Azores, flora of
+</item>
+
+<item>
+Babington, Mr., on British plants
+</item>
+
+<item>
+Balancement of growth
+</item>
+
+<item>
+Bamboo with hooks
+</item>
+
+<item>
+Barberry, flowers of
+</item>
+
+<item>
+Barrande, M., on Silurian colonies; on the succession of species; on
+parallelism of palaeozoic formations; on affinities of ancient species
+</item>
+
+<item>
+Barriers, importance of
+</item>
+
+<item>
+Batrachians on islands
+</item>
+
+<item>
+Bats, how structure acquired; distribution of
+</item>
+
+<item>
+Bear, catching water-insects
+</item>
+
+<item>
+Bee, sting of; queen, killing rivals
+</item>
+
+<item>
+Bees fertilizing flowers; hive; not sucking the red clover; cell-making
+instinct; humble, cells of; parasitic
+</item>
+
+<item>
+Beetles, wingless, in Madeira; with deficient tarsi
+</item>
+
+<item>
+Bentham, Mr., on British plants; on classification
+</item>
+
+<item>
+Berkeley, Mr., on seeds in salt-water
+</item>
+
+<item>
+Bermuda, birds of
+</item>
+
+<item>
+Birds acquiring fear; annually cross the Atlantic; colour of, on
+continents; fossil, in caves of Brazil; of Madeira, Bermuda, and Galapagos;
+song of males; transporting seeds; waders; wingless; with traces of
+embryonic teeth
+</item>
+
+<item>
+Bizcacha, affinities of
+</item>
+
+<item>
+Bladder for swimming in fish
+</item>
+
+<item>
+Blindness of cave animals
+</item>
+
+<item>
+Blyth, Mr., on distinctness of Indian cattle; on striped Hemionus; on
+crossed geese
+</item>
+
+<item>
+Boar; shoulder-pad of
+</item>
+
+<item>
+Borrow, Mr., on the Spanish pointer
+</item>
+
+<item>
+Bory St. Vincent, on Batrachians
+</item>
+
+<item>
+Bosquet, M., on fossil Chthamalus
+</item>
+
+<item>
+Boulders, erratic, on the Azores
+</item>
+
+<item>
+Branchiae
+</item>
+
+<item>
+Brent, Mr., on house-tumblers; on hawks killing pigeons
+</item>
+
+<item>
+Brewer, Dr., on American cuckoo
+</item>
+
+<item>
+Britain, mammals of
+</item>
+
+<item>
+Bronn, on duration of specific forms
+</item>
+
+<item>
+Brown, Robert, on classification
+</item>
+
+<item>
+Buckman, on variation in plants
+</item>
+
+<item>
+Buzareingues on sterility of varieties
+</item>
+
+<item>
+Cabbage, varieties of, crossed
+</item>
+
+<item>
+Calceolaria
+</item>
+
+<item>
+Canary-birds, sterility of hybrids
+</item>
+
+<item>
+Cape de Verde islands
+</item>
+
+<item>
+Cape of Good Hope, plants of
+</item>
+
+<item>
+Carrier-pigeons killed by hawks
+</item>
+
+<item>
+Cassini on flowers of composita
+</item>
+
+<item>
+Catasetum
+</item>
+
+<item>
+Cats, with blue eyes, deaf; variation in habits of; curling tail when going
+to spring
+</item>
+
+<item>
+Cattle destroying fir-trees; destroyed by flies in La Plata; breeds of,
+locally extinct; fertility of Indian and European breeds
+</item>
+
+<item>
+Cave, inhabitants of, blind
+</item>
+
+<item>
+Centres of creation
+</item>
+
+<item>
+Cephalopodae, development of
+</item>
+
+<item>
+Cervulus
+</item>
+
+<item>
+Cetacea, teeth and hair
+</item>
+
+<item>
+Ceylon, plants of
+</item>
+
+<item>
+Chalk formation
+</item>
+
+<item>
+Charlock
+</item>
+
+<item>
+Checks to increase; mutual
+</item>
+
+<item>
+Chickens, instinctive tameness of
+</item>
+
+<item>
+Chthamalinae
+</item>
+
+<item>
+Chthamalus, cretacean species of
+</item>
+
+<item>
+Circumstances favourable to selection of domestic products; to natural
+selection
+</item>
+
+<item>
+Cirripedes capable of crossing; carapace aborted; their ovigerous frena;
+fossil; larvae of
+</item>
+
+<item>
+Clift, Mr., on the succession of types
+</item>
+
+<item>
+Climate, effects of, in checking increase of beings; adaptation of, to
+organisms
+</item>
+
+<item>
+Cobites, intestine of
+</item>
+
+<item>
+Cockroach
+</item>
+
+<item>
+Collections, palaeontological, poor
+</item>
+
+<item>
+Colour, influenced by climate; in relation to attacks by flies
+</item>
+
+<item>
+Columba livia, parent of domestic pigeons
+</item>
+
+<item>
+Colymbetes
+</item>
+
+<item>
+Compositae, outer and inner florets of; male flowers of
+</item>
+
+<item>
+Conclusion, general
+</item>
+
+<item>
+Conditions, slight changes in, favourable to fertility
+</item>
+
+<item>
+Coot
+</item>
+
+<item>
+Coral-islands, seeds drifted to; reefs, indicating movements of earth
+</item>
+
+<item>
+Corn-crake
+</item>
+
+<item>
+Correlation of growth in domestic productions; of growth
+</item>
+
+<item>
+Cowslip
+</item>
+
+<item>
+Creation, single centres of
+</item>
+
+<item>
+Crinum
+</item>
+
+<item>
+Crosses, reciprocal
+</item>
+
+<item>
+Crossing of domestic animals, importance in altering breeds; advantages of;
+unfavourable to selection
+</item>
+
+<item>
+Crustacea of New Zealand
+</item>
+
+<item>
+Crustacean, blind
+</item>
+
+<item>
+Cryptocerus
+</item>
+
+<item>
+Ctenomys, blind
+</item>
+
+<item>
+Cuckoo, instinct of
+</item>
+
+<item>
+Currants, grafts of
+</item>
+
+<item>
+Currents of sea, rate of
+</item>
+
+<item>
+Cuvier on conditions of existence; on fossil monkeys; Fred., on instinct
+</item>
+
+<item>
+Dana, Prof., on blind cave-animals; on relations of crustaceans of Japan,
+on crustaceans of New Zealand
+</item>
+
+<item>
+De Candolle on struggle for existence; on umbelliferae; on general
+affinities; Alph., on low plants, widely dispersed; on widely-ranging
+plants being variable; on naturalisation; on winged seeds; on Alpine
+species suddenly becoming rare; on distribution of plants with large seeds;
+on vegetation of Australia; on fresh-water plants; on insular plants
+</item>
+
+<item>
+Degradation of coast-rocks
+</item>
+
+<item>
+Denudation, rate of; of oldest rocks
+</item>
+
+<item>
+Development of ancient forms
+</item>
+
+<item>
+Devonian system
+</item>
+
+<item>
+Dianthus, fertility of crosses
+</item>
+
+<item>
+Dirt on feet of birds
+</item>
+
+<item>
+Division, physiological, of labour
+</item>
+
+<item>
+Dogs, hairless, with imperfect teeth; descended from several wild stocks;
+domestic instincts of; inherited civilisation of; fertility of breeds
+together; of crosses; proportions of, when young
+</item>
+
+<item>
+Downing, Mr., on fruit-trees in America
+</item>
+
+<item>
+Downs, North and South
+</item>
+
+<item>
+Dragon-flies, intestines of
+</item>
+
+<item>
+Drift-timber
+</item>
+
+<item>
+Driver-ant
+</item>
+
+<item>
+Drones killed by other bees
+</item>
+
+<item>
+Duck, domestic, wings of, reduced; logger-headed
+</item>
+
+<item>
+Duckweed
+</item>
+
+<item>
+Dugong, affinities of
+</item>
+
+<item>
+Dung-beetles with deficient tarsi
+</item>
+
+<item>
+Dyticus
+</item>
+
+<item>
+Earl, Mr., W., on the Malay Archipelago
+</item>
+
+<item>
+Ears, drooping, in domestic animals; rudimentary
+</item>
+
+<item>
+Earth, seeds in roots of trees
+</item>
+
+<item>
+Eciton
+</item>
+
+<item>
+Edentata, teeth and hair; fossil species of
+</item>
+
+<item>
+Edwards, Milne, on physiological divisions of labour; on gradations of
+structure; on embryological characters
+</item>
+
+<item>
+Eggs, young birds escaping from
+</item>
+
+<item>
+Electric organs
+</item>
+
+<item>
+Elephant, rate increase; of glacial period
+</item>
+
+<item>
+Existence, struggle for; conditions of
+</item>
+
+<item>
+Eye, structure of; correction for aberration
+</item>
+
+<item>
+Eyes reduced in moles
+</item>
+
+<item>
+Fabre, M., on parasitic sphex
+</item>
+
+<item>
+Falconer, Dr., on naturalisation of plants in India; on fossil crocodile;
+on elephants and mastodons; and Cautley on mammals of sub-Himalayan beds
+</item>
+
+<item>
+Falkland Island, wolf of
+</item>
+
+<item>
+Faults
+</item>
+
+<item>
+Fear, instinctive, in birds
+</item>
+
+<item>
+Feet of birds, young molluscs adhering to
+</item>
+
+<item>
+Fertility of hybrids, from slight changes in conditions; of crossed
+varieties
+</item>
+
+<item>
+Fir-trees destroyed by cattle; pollen of
+</item>
+
+<item>
+Fish, flying; teleostean, sudden appearance of; eating seeds; fresh-water,
+distribution of
+</item>
+
+<item>
+Fishes, ganoid, now confined to fresh water; electric organs of; of
+southern hemisphere
+</item>
+
+<item>
+Flight, powers of, how acquired
+</item>
+
+<item>
+Flowers, structure of; in relation to crossing; of composite and
+umbelliferae
+</item>
+
+<item>
+Forbes, E., on colours of shells; on abrupt range of shells in depth; on
+poorness of palaeontological collections; on continuous succession of
+genera; on continental extensions; on distribution during glacial period;
+on parallelism in time and space
+</item>
+
+<item>
+Forests, changes in, in America
+</item>
+
+<item>
+Formation, Devonian
+</item>
+
+<item>
+Formations, thickness of, in Britain; intermittent
+</item>
+
+<item>
+Formica rufescens; sanguinea; flava, neuter of
+</item>
+
+<item>
+Frena, ovigerous, of cirripedes
+</item>
+
+<item>
+Fresh-water productions, dispersal of
+</item>
+
+<item>
+Fries on species in large genera being closely allied to other species
+</item>
+
+<item>
+Frigate-bird
+</item>
+
+<item>
+Frogs on islands
+</item>
+
+<item>
+Fruit-trees, gradual improvement of; in United States; varieties of,
+acclimatised in United States
+</item>
+
+<item>
+Fuci, crossed
+</item>
+
+<item>
+Fur, thicker in cold climates
+</item>
+
+<item>
+Furze
+</item>
+
+<item>
+Galapagos Archipelago, birds of; productions of
+</item>
+
+<item>
+Galeopithecus
+</item>
+
+<item>
+Game, increase of, checked by vermin
+</item>
+
+<item>
+Gartner on sterility of hybrids; on reciprocal crosses; on crossed maize
+and verbascum; on comparison of hybrids and mongrels
+</item>
+
+<item>
+Geese, fertility when crossed; upland
+</item>
+
+<item>
+Genealogy important in classification
+</item>
+
+<item>
+Geoffroy St. Hilaire on balancement; on homologous organs; Isidore, on
+variability of repeated parts; on correlation in monstrosities; on
+correlation; on variable parts being often monstrous
+</item>
+
+<item>
+Geographical distribution
+</item>
+
+<item>
+Geology, future progress of
+</item>
+
+<item>
+Giraffe, tail of
+</item>
+
+<item>
+Glacial period
+</item>
+
+<item>
+Gmelin on Distribution
+</item>
+
+<item>
+Gnathodon, fossil
+</item>
+
+<item>
+Godwin-Austin, Mr., on the Malay Archipelago
+</item>
+
+<item>
+Goethe on compensation of growth
+</item>
+
+<item>
+Gooseberry, grafts of
+</item>
+
+<item>
+Gould, Dr. A., on land-shells; Mr., on colours of birds; on birds of the
+Galapagos; on distribution of genera of birds
+</item>
+
+<item>
+Gourds, crossed
+</item>
+
+<item>
+Grafts, capacity of
+</item>
+
+<item>
+Grasses, varieties of
+</item>
+
+<item>
+Gray, Dr. Asa, on trees of United States; on naturalised plants in the
+United States; on rarity of intermediate varieties; on Alpine plants; Dr.
+J.E., on striped mule
+</item>
+
+<item>
+Grebe
+</item>
+
+<item>
+Grouse, colours of; red, a doubtful species
+</item>
+
+<item>
+Growth, compensation of; correlation of, in domestic products; correlation
+of
+</item>
+
+<item>
+Habit, effect of, under domestication; effect of, under nature;
+diversified, of same species
+</item>
+
+<item>
+Hair and teeth, correlated
+</item>
+
+<item>
+Harcourt, Mr. E.V., on the birds of Madeira
+</item>
+
+<item>
+Hartung, M., on boulders in the Azores
+</item>
+
+<item>
+Hazel-nuts
+</item>
+
+<item>
+Hearne on habits of bears
+</item>
+
+<item>
+Heath, changes in vegetation
+</item>
+
+<item>
+Heer, O., on plants of Madeira
+</item>
+
+<item>
+Helix pomatia
+</item>
+
+<item>
+Helosciadium
+</item>
+
+<item>
+Hemionus, striped
+</item>
+
+<item>
+Herbert, W., on struggle for existence; on sterility of hybrids
+</item>
+
+<item>
+Hermaphrodites crossing
+</item>
+
+<item>
+Heron eating seed
+</item>
+
+<item>
+Heron, Sir R., on peacocks
+</item>
+
+<item>
+Heusinger, on white animals not poisoned by certain plants
+</item>
+
+<item>
+Hewitt, Mr., on sterility of first crosses
+</item>
+
+<item>
+Himalaya, glaciers of; plants of
+</item>
+
+<item>
+Hippeastrum
+</item>
+
+<item>
+Holly-trees, sexes of
+</item>
+
+<item>
+Hollyhock, varieties of, crossed
+</item>
+
+<item>
+Hooker, Dr., on trees of New Zealand
+</item>
+
+<item>
+Hooker, Dr., on acclimatisation of Himalayan trees; on flowers of
+umbelliferae; on glaciers of Himalaya; on algae of New Zealand; on
+vegetation at the base of the Himalaya; on plants of Tierra del Fuego; on
+Australian plants; on relations of flora of South America; on flora of the
+Antarctic lands; on the plants of the Galapagos
+</item>
+
+<item>
+Hooks on bamboos; to seeds on islands
+</item>
+
+<item>
+Horner, Mr., on the antiquity of Egyptians
+</item>
+
+<item>
+Horns, rudimentary
+</item>
+
+<item>
+Horse, fossil, in La Plata
+</item>
+
+<item>
+Horses destroyed by flies in La Plata; striped; proportions of, when young
+</item>
+
+<item>
+Horticulturists, selection applied by
+</item>
+
+<item>
+Huber on cells of bees; P., on reason blended with instinct; on habitual
+nature of instincts; on slave-making ants; on Melipona domestica
+</item>
+
+<item>
+Humble-bees; cells of
+</item>
+
+<item>
+Hunter, J., on secondary sexual characters
+</item>
+
+<item>
+Hutton, Captain, on crossed geese
+</item>
+
+<item>
+Huxley, Prof., on structure of hermaphrodites; on embryological succession;
+on homologous organs; on the development of aphis
+</item>
+
+<item>
+Hybrids and mongrels compared
+</item>
+
+<item>
+Hybridism
+</item>
+
+<item>
+Hydra, structure of
+</item>
+
+<item>
+Ibla
+</item>
+
+<item>
+Icebergs transporting seeds
+</item>
+
+<item>
+Individuals, numbers favourable to selection; many, whether simultaneously
+created
+</item>
+
+<item>
+Insects, colour of, fitted for habitation; sea-side colours of; blind, in
+caves; luminous; neuter
+</item>
+
+<item>
+Instincts, domestic
+</item>
+
+<item>
+Intercrossing, advantages of
+</item>
+
+<item>
+Japan, productions of
+</item>
+
+<item>
+Java, plants of
+</item>
+
+<item>
+Jones, Mr. J.M., on the birds of Bermuda
+</item>
+
+<item>
+Jussieu on classification
+</item>
+
+<item>
+Kentucky, caves of
+</item>
+
+<item>
+Kerguelen-land, flora of
+</item>
+
+<item>
+Kidney-bean, acclimatisation of
+</item>
+
+<item>
+Kidneys of birds
+</item>
+
+<item>
+Kirby on tarsi deficient in beetles
+</item>
+
+<item>
+Knight, Andrew, on cause of variation
+</item>
+
+<item>
+Kolreuter on the barberry; on sterility of hybrids; on reciprocal crosses;
+on crossed varieties of nicotiana; on crossing male and hermaphrodite
+flowers
+</item>
+
+<item>
+Land-shells, distribution of, of Madeira, naturalised
+</item>
+
+<item>
+Languages, classification of
+</item>
+
+<item>
+Lapse, great, of time
+</item>
+
+<item>
+Larvae
+</item>
+
+<item>
+Laurel, nectar secreted by the leaves
+</item>
+
+<item>
+Laws of variation
+</item>
+
+<item>
+Leech, varieties of
+</item>
+
+<item>
+Leguminosae, nectar secreted by glands
+</item>
+
+<item>
+Lepidosiren
+</item>
+
+<item>
+Life, struggle for
+</item>
+
+<item>
+Lingula, Silurian
+</item>
+
+<item>
+Linnaeus, aphorism of
+</item>
+
+<item>
+Lion, mane of; young of, striped
+</item>
+
+<item>
+Lobelia fulgens
+</item>
+
+<item>
+Lobelia, sterility of crosses
+</item>
+
+<item>
+Loess of the Rhine
+</item>
+
+<item>
+Lowness of structure connected with variability
+</item>
+
+<item>
+Lowness, related to wide distribution
+</item>
+
+<item>
+Lubbock, Mr., on the nerves of coccus
+</item>
+
+<item>
+Lucas, Dr. P., on inheritance; on resemblance of child to parent
+</item>
+
+<item>
+Lund and Clausen on fossils of Brazil
+</item>
+
+<item>
+Lyell, Sir C., on the struggle for existence; on modern changes of the
+earth; on measure of denudation; on a carboniferous land-shell; on fossil
+whales; on strata beneath Silurian system; on the imperfection of the
+geological record; on the appearance of species; on Barrande's colonies; on
+tertiary formations of Europe and North America; on parallelism of tertiary
+formations; on transport of seeds by icebergs; on great alternations of
+climate; on the distribution of fresh-water shells; on land-shells of
+Madeira
+</item>
+
+<item>
+Lyell and Dawson on fossilized trees in Nova Scotia
+</item>
+
+<item>
+Macleay on analogical characters
+</item>
+
+<item>
+Madeira, plants of; beetles of, wingless; fossil land-shells of; birds of
+</item>
+
+<item>
+Magpie tame in Norway
+</item>
+
+<item>
+Maize, crossed
+</item>
+
+<item>
+Malay Archipelago compared with Europe; mammals of
+</item>
+
+<item>
+Malpighiaceae
+</item>
+
+<item>
+Mammae, rudimentary
+</item>
+
+<item>
+Mammals, fossil, in secondary formation; insular
+</item>
+
+<item>
+Man, origin of races of
+</item>
+
+<item>
+Manatee, rudimentary nails of
+</item>
+
+<item>
+Marsupials of Australia, fossil species of
+</item>
+
+<item>
+Martens, M., experiment on seeds
+</item>
+
+<item>
+Martin, Mr. W.C., on striped mules
+</item>
+
+<item>
+Matteuchi on the electric organs of rays
+</item>
+
+<item>
+Matthiola, reciprocal crosses of
+</item>
+
+<item>
+Means of dispersal
+</item>
+
+<item>
+Melipona domestica
+</item>
+
+<item>
+Metamorphism of oldest rocks
+</item>
+
+<item>
+Mice destroying bees; acclimatisation of
+</item>
+
+<item>
+Migration, bears on first appearance of fossils
+</item>
+
+<item>
+Miller, Prof., on the cells of bees
+</item>
+
+<item>
+Mirabilis, crosses of
+</item>
+
+<item>
+Missel-thrush
+</item>
+
+<item>
+Misseltoe, complex relations of
+</item>
+
+<item>
+Mississippi, rate of deposition at mouth
+</item>
+
+<item>
+Mocking-thrush of the Galapagos
+</item>
+
+<item>
+Modification of species, how far applicable
+</item>
+
+<item>
+Moles, blind
+</item>
+
+<item>
+Mongrels, fertility and sterility of; and hybrids compared
+</item>
+
+<item>
+Monkeys, fossil
+</item>
+
+<item>
+Monocanthus
+</item>
+
+<item>
+Mons, Van, on the origin of fruit-trees
+</item>
+
+<item>
+Mozart, musical powers of
+</item>
+
+<item>
+Mud, seeds in
+</item>
+
+<item>
+Mules, striped
+</item>
+
+<item>
+Muller, Dr. F., on Alpine Australian plants
+</item>
+
+<item>
+Murchison, Sir, R., on the formations of Russia; on azoic formations; on
+extinction
+</item>
+
+<item>
+Mustela vison
+</item>
+
+<item>
+Myanthus
+</item>
+
+<item>
+Myrmecocystus
+</item>
+
+<item>
+Myrmica, eyes of
+</item>
+
+<item>
+Nails, rudimentary
+</item>
+
+<item>
+Natural history, future progress of
+</item>
+
+<item>
+Naturalisation of forms distinct from the indigenous species; in New
+Zealand
+</item>
+
+<item>
+Nautilus, Silurian
+</item>
+
+<item>
+Nectar of plants
+</item>
+
+<item>
+Nectaries, how formed
+</item>
+
+<item>
+Nelumbium luteum
+</item>
+
+<item>
+Nests, variation in
+</item>
+
+<item>
+Neuter insects
+</item>
+
+<item>
+New Zealand, productions of, not perfect; naturalised products of; fossil
+birds of; glacial action in; crustaceans of; algae of; number of plants of;
+flora of
+</item>
+
+<item>
+Nicotiana, crossed varieties of; certain species very sterile
+</item>
+
+<item>
+Noble, Mr., on fertility of Rhododendron
+</item>
+
+<item>
+Nodules, phosphatic, in azoic rocks
+</item>
+
+<item>
+Oak, varieties of
+</item>
+
+<item>
+Onites apelles
+</item>
+
+<item>
+Orchis, pollen of
+</item>
+
+<item>
+Ornithorhynchus
+</item>
+
+<item>
+Ostrich not capable of flight; habit of laying eggs together; American, two
+species of
+</item>
+
+<item>
+Otter, habits of, how acquired
+</item>
+
+<item>
+Ouzel, water
+</item>
+
+<item>
+Owen, Prof., on birds not flying; on vegetative repetition; on variable
+length of arms in ourang-outang; on the swim-bladder of fishes; on electric
+organs; on fossil horse of La Plata; on relations of ruminants and
+pachyderms; on fossil birds of New Zealand; on succession of types; on
+affinities of the dugong; on homologous organs; on the metamorphosis of
+cephalopods and spiders
+</item>
+
+<item>
+Pacific Ocean, faunas of
+</item>
+
+<item>
+Paley, on no organ formed to give pain
+</item>
+
+<item>
+Pallas, on the fertility of the wild stocks of domestic animals
+</item>
+
+<item>
+Paraguay, cattle destroyed by flies
+</item>
+
+<item>
+Parasites
+</item>
+
+<item>
+Partridge, dirt on feet
+</item>
+
+<item>
+Parts greatly developed, variable, degrees of utility of
+</item>
+
+<item>
+Parus major
+</item>
+
+<item>
+Passiflora
+</item>
+
+<item>
+Peaches in United States
+</item>
+
+<item>
+Pear, grafts of
+</item>
+
+<item>
+Pelargonium, flowers of, sterility of
+</item>
+
+<item>
+Peloria
+</item>
+
+<item>
+Pelvis of women
+</item>
+
+<item>
+Period, glacial
+</item>
+
+<item>
+Petrels, habits of
+</item>
+
+<item>
+Phasianus, fertility of hybrids
+</item>
+
+<item>
+Pheasant, young, wild
+</item>
+
+<item>
+Pictet, Prof., on groups of species suddenly appearing; on rate of organic
+change; on continuous succession of genera; on close alliance of fossils in
+consecutive formations; on embryological succession
+</item>
+
+<item>
+Pierce, Mr., on varieties of wolves
+</item>
+
+<item>
+Pigeons with feathered feet and skin between toes; breeds described, and
+origin of; breeds of, how produced; tumbler, not being able to get out of
+egg; reverting to blue colour; instinct of tumbling; carriers, killed by
+hawks; young of
+</item>
+
+<item>
+Pistil, rudimentary
+</item>
+
+<item>
+Plants, poisonous, not affecting certain coloured animals; selection
+applied to; gradual improvement of; not improved in barbarous countries;
+destroyed by insects; in midst of range, have to struggle with other
+plants; nectar of; fleshy, on sea-shores; fresh-water, distribution of; low
+in scale; widely distributed
+</item>
+
+<item>
+Plumage, laws of change in sexes of birds
+</item>
+
+<item>
+Plums in the United States
+</item>
+
+<item>
+Pointer dog, origin of; habits of
+</item>
+
+<item>
+Poison not affecting certain coloured animals
+</item>
+
+<item>
+Poison, similar effect of, on animals and plants
+</item>
+
+<item>
+Pollen of fir-trees
+</item>
+
+<item>
+Poole, Col., on striped hemionus
+</item>
+
+<item>
+Prestwich, Mr., on English and French eocene formation
+</item>
+
+<item>
+Primrose; sterility of
+</item>
+
+<item>
+Primula, varieties of
+</item>
+
+<item>
+Proteolepas
+</item>
+
+<item>
+Proteus
+</item>
+
+<item>
+Psychology, future progress of
+</item>
+
+<item>
+Quagga, striped
+</item>
+
+<item>
+Quince, grafts of
+</item>
+
+<item>
+Rabbit, disposition of young
+</item>
+
+<item>
+Race-horses, Arab; English
+</item>
+
+<item>
+Races, domestic, characters of
+</item>
+
+<item>
+Ramond on plants of Pyrenees
+</item>
+
+<item>
+Ramsay, Prof., on thickness of the British formations; on faults
+</item>
+
+<item>
+Ratio of increase
+</item>
+
+<item>
+Rats, supplanting each other; acclimatisation of; blind in cave
+</item>
+
+<item>
+Rattle-snake
+</item>
+
+<item>
+Reason and instinct
+</item>
+
+<item>
+Recapitulation, general
+</item>
+
+<item>
+Reciprocity of crosses
+</item>
+
+<item>
+Record, geological, imperfect
+</item>
+
+<item>
+Rengger on flies destroying cattle
+</item>
+
+<item>
+Resemblance to parents in mongrels and hybrids
+</item>
+
+<item>
+Reversion, law of inheritance
+</item>
+
+<item>
+Rhododendron, sterility of
+</item>
+
+<item>
+Richard, Prof., on Aspicarpa
+</item>
+
+<item>
+Richardson, Sir J., on structure of squirrels; on fishes of the southern
+hemisphere
+</item>
+
+<item>
+Robinia, grafts of
+</item>
+
+<item>
+Rodents, blind
+</item>
+
+<item>
+Rudimentary organs
+</item>
+
+<item>
+Rudiments important for classification
+</item>
+
+<item>
+Sageret on grafts
+</item>
+
+<item>
+Salmons, males fighting, and hooked jaws of
+</item>
+
+<item>
+Salt-water, how far injurious to seeds
+</item>
+
+<item>
+Saurophagus sulphuratus
+</item>
+
+<item>
+Schiodte on blind insects
+</item>
+
+<item>
+Schlegel on snakes
+</item>
+
+<item>
+Sea-water, how far injurious to seeds
+</item>
+
+<item>
+Sebright, Sir J., on crossed animals; on selection of pigeons
+</item>
+
+<item>
+Sedgwick, Prof., on groups of species suddenly appearing
+</item>
+
+<item>
+Seedlings destroyed by insects
+</item>
+
+<item>
+Seeds, nutriment in; winged; power of resisting salt-water; in crops and
+intestines of birds; eaten by fish; in mud; hooked, on islands
+</item>
+
+<item>
+Selection of domestic products, principle not of recent origin;
+unconscious; natural; sexual; natural, circumstances favourable to
+</item>
+
+<item>
+Sexes, relations of
+</item>
+
+<item>
+Sexual characters variable; selection
+</item>
+
+<item>
+Sheep, Merino, their selection; two sub-breeds unintentionally produced;
+mountain, varieties of
+</item>
+
+<item>
+Shells, colours of, littoral, seldom embedded; fresh-water, dispersal of;
+of Madeira; land, distribution of
+</item>
+
+<item>
+Silene, fertility of crosses
+</item>
+
+<item>
+Silliman, Prof., on blind rat
+</item>
+
+<item>
+Skulls of young mammals
+</item>
+
+<item>
+Slave-making instinct
+</item>
+
+<item>
+Smith, Col. Hamilton, on striped horses; Mr. Fred., on slave-making ants;
+Mr., of Jordan Hill, on degradation of coast-rocks
+</item>
+
+<item>
+Snap-dragon
+</item>
+
+<item>
+Somerville, Lord, on selection of sheep
+</item>
+
+<item>
+Sorbus, grafts of
+</item>
+
+<item>
+Spaniel, King Charles's breed
+</item>
+
+<item>
+Species, groups of, suddenly appearing; beneath Silurian formations;
+successively appearing; changing simultaneously throughout the world
+</item>
+
+<item>
+Spencer, Lord, on increase in size of cattle
+</item>
+
+<item>
+Sphex, parasitic
+</item>
+
+<item>
+Spiders, development of
+</item>
+
+<item>
+Spitz-dog crossed with fox
+</item>
+
+<item>
+Sports in plants
+</item>
+
+<item>
+Sprengel, C.C., on crossing; on ray-florets
+</item>
+
+<item>
+Squirrels, gradations in structure
+</item>
+
+<item>
+Staffordshire, heath, changes in
+</item>
+
+<item>
+Stag-beetles, fighting
+</item>
+
+<item>
+Sterility from changed conditions of life; of hybrids; laws of; causes of;
+from unfavourable conditions; of certain varieties
+</item>
+
+<item>
+St. Helena, productions of
+</item>
+
+<item>
+St. Hilaire, Aug., on classification
+</item>
+
+<item>
+St. John, Mr., on habits of cats
+</item>
+
+<item>
+Sting of bee
+</item>
+
+<item>
+Stocks, aboriginal, of domestic animal
+</item>
+
+<item>
+Strata, thickness of, in Britain
+</item>
+
+<item>
+Stripes of horses
+</item>
+
+<item>
+Swallow, one species supplanting another
+</item>
+
+<item>
+Swim-bladder
+</item>
+
+<item>
+Tail of giraffe; of aquatic animals; rudimentary
+</item>
+
+<item>
+Tarsi deficient
+</item>
+
+<item>
+Tausch on umbelliferous flowers
+</item>
+
+<item>
+Teeth and hair correlated; embryonic, traces of, in birds; rudimentary, in
+embryonic calf
+</item>
+
+<item>
+Tegetmeier, Mr., on cells of bees
+</item>
+
+<item>
+Temminck on distribution aiding classification
+</item>
+
+<item>
+Thouin on grafts
+</item>
+
+<item>
+Thrush, aquatic species of; mocking, of the Galapagos; young of, spotted;
+nest of
+</item>
+
+<item>
+Thuret, M., on crossed fuci
+</item>
+
+<item>
+Thwaites, Mr., on acclimatisation
+</item>
+
+<item>
+Tierra del Fuego, dogs of; plants of
+</item>
+
+<item>
+Timber-drift
+</item>
+
+<item>
+Time, lapse of
+</item>
+
+<item>
+Titmouse
+</item>
+
+<item>
+Toads on islands
+</item>
+
+<item>
+Tobacco, crossed varieties of
+</item>
+
+<item>
+Tomes, Mr., on the distribution of bats
+</item>
+
+<item>
+Transitions in varieties
+</item>
+
+<item>
+Trees on islands belong to peculiar orders; with separated sexes
+</item>
+
+<item>
+Trifolium pratense; incarnatum
+</item>
+
+<item>
+Trigonia
+</item>
+
+<item>
+Trilobites; sudden extinction of
+</item>
+
+<item>
+Troglodytes
+</item>
+
+<item>
+Tucutucu, blind
+</item>
+
+<item>
+Tumbler pigeons, habits of, hereditary; young of
+</item>
+
+<item>
+Turkey-cock, brush of hair on breast
+</item>
+
+<item>
+Turkey, naked skin on head; young, wild
+</item>
+
+<item>
+Turnip and cabbage, analogous variations of
+</item>
+
+<item>
+Type, unity of
+</item>
+
+<item>
+Types, succession of, in same areas
+</item>
+
+<item>
+Udders enlarged by use; rudimentary
+</item>
+
+<item>
+Ulex, young leaves of
+</item>
+
+<item>
+Umbelliferae, outer and inner florets of
+</item>
+
+<item>
+Unity of type
+</item>
+
+<item>
+Use, effects of, under domestication
+</item>
+
+<item>
+Utility, how far important in the construction of each part
+</item>
+
+<item>
+Valenciennes on fresh-water fish
+</item>
+
+<item>
+Variability of mongrels and hybrids
+</item>
+
+<item>
+Variations appear at corresponding ages; analogous in distinct species
+</item>
+
+<item>
+Varieties, natural; struggle between; domestic, extinction of;
+transitional; when crossed, fertile; when crossed, sterile; classification
+of
+</item>
+
+<item>
+Verbascum, sterility of; varieties of, crossed
+</item>
+
+<item>
+Verneuil, M. de, on the succession of species
+</item>
+
+<item>
+Viola tricolor
+</item>
+
+<item>
+Volcanic islands, denudation of
+</item>
+
+<item>
+Vulture, naked skin on head
+</item>
+
+<item>
+Wading-birds
+</item>
+
+<item>
+Wallace, Mr., on origin of species; on law of geographical distribution; on
+the Malay Archipelago
+</item>
+
+<item>
+Wasp, sting of
+</item>
+
+<item>
+Water, fresh, productions of
+</item>
+
+<item>
+Water-hen
+</item>
+
+<item>
+Waterhouse, Mr., on Australian marsupials; on greatly developed parts being
+variable; on the cells of bees; on general affinities
+</item>
+
+<item>
+Water-ouzel
+</item>
+
+<item>
+Watson, Mr. H.C., on range of varieties of British plants; on
+acclimatisation; on flora of Azores; on Alpine plants; on rarity of
+intermediate varieties
+</item>
+
+<item>
+Weald, denudation of
+</item>
+
+<item>
+Web of feet in water-birds
+</item>
+
+<item>
+West Indian islands, mammals of
+</item>
+
+<item>
+Westwood on species in large genera being closely allied to others; on the
+tarsi of Engidae; on the antennae of hymenopterous insects
+</item>
+
+<item>
+Whales, fossil
+</item>
+
+<item>
+Wheat, varieties of
+</item>
+
+<item>
+White Mountains, flora of
+</item>
+
+<item>
+Wings, reduction of size
+</item>
+
+<item>
+Wings of insects homologous with branchiae; rudimentary, in insects
+</item>
+
+<item>
+Wolf crossed with dog; of Falkland Isles
+</item>
+
+<item>
+Wollaston, Mr., on varieties of insects; on fossil varieties of land-shells
+in Madeira; on colours of insects on sea-shore; on wingless beetles; on
+rarity of intermediate varieties; on insular insects; on land-shells of
+Madeira, naturalised
+</item>
+
+<item>
+Wolves, varieties of
+</item>
+
+<item>
+Woodpecker, habits of; green colour of
+</item>
+
+<item>
+Woodward, Mr., on the duration of specific forms; on the continuous
+succession of genera; on the succession of types
+</item>
+
+<item>
+World, species changing simultaneously throughout
+</item>
+
+<item>
+Wrens, nest of
+</item>
+
+<item>
+Youatt, Mr., on selection, on sub-breeds of sheep; on rudimentary horns in
+young cattle
+</item>
+
+<item>
+Zebra, stripes on 
+</item>
+
+</index>
+</backmatter>
+</book>
+<endgutblurb>
+End of this Project Gutenberg Etext of the First Edition of On the Origin
+of Species by Charles Darwin
+</endgutblurb>
+</gutbook>
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/import/owlcreek.xml
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/import/owlcreek.xml	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/import/owlcreek.xml	(revision 14125)
@@ -0,0 +1,869 @@
+<?xml version="1.0"?>
+<!DOCTYPE gutbook SYSTEM "gutbook1.dtd">
+
+<?xml-stylesheet type="text/css" href="darwin.css"?>
+
+<gutbook>
+<gutblurb>
+<para>
+The Project Gutenberg Etext of An Occurrence at Owl Creek Bridge
+</para>
+
+<para>
+[This was the #1 rated Twilight Zone epidose of all time]
+#2 in our Ambrose Bierce series
+</para>
+
+<para>
+Copyright laws are changing all over the world, be sure to check
+the copyright laws for your country before posting these files!!
+</para>
+
+<para>
+Please take a look at the important information in this header.
+We encourage you to keep this file on your own disk, keeping an
+electronic path open for the next readers.  Do not remove this.
+</para>
+
+<para>
+**Welcome To The World of Free Plain Vanilla Electronic Texts**
+</para>
+
+<para>
+**Etexts Readable By Both Humans and By Computers, Since 1971**
+</para>
+
+<para>
+*These Etexts Prepared By Hundreds of Volunteers and Donations*
+</para>
+
+<para>
+Information on contacting Project Gutenberg to get Etexts, and
+further information is included below.  We need your donations.
+</para>
+
+<para>
+An Occurrence At Owl Creek Bridge
+</para>
+
+<para>
+by Ambrose Bierce
+</para>
+
+<para>
+December, 1995  [Etext #375]
+</para>
+
+<para>
+The Project Gutenberg Etext of An Occurrence at Owl Creek Bridge
+*****This file should be named owlcr10.txt or owlcr10.zip******
+</para>
+
+<para>
+Corrected EDITIONS of our etexts get a new NUMBER, owlcr11.txt.
+VERSIONS based on separate sources get new LETTER, owlcr10a.txt.
+</para>
+
+<para>
+We are now trying to release all our books one month in advance
+of the official release dates, for time for better editing.
+</para>
+
+<para>
+Please note:  neither this list nor its contents are final till
+midnight of the last day of the month of any such announcement.
+The official release date of all Project Gutenberg Etexts is at
+Midnight, Central Time, of the last day of the stated month.  A
+preliminary version may often be posted for suggestion, comment
+and editing by those who wish to do so.  To be sure you have an
+up to date first edition [xxxxx10x.xxx] please check file sizes
+in the first week of the next month.  Since our ftp program has
+a bug in it that scrambles the date [tried to fix and failed] a
+look at the file size will have to do, but we will try to see a
+new copy has at least one byte more or less.
+</para>
+
+<para>
+Information about Project Gutenberg (one page)
+</para>
+
+<para>
+We produce about two million dollars for each hour we work.  The
+fifty hours is one conservative estimate for how long it we take
+to get any etext selected, entered, proofread, edited, copyright
+searched and analyzed, the copyright letters written, etc.  This
+projected audience is one hundred million readers.  If our value
+per text is nominally estimated at one dollar then we produce $4
+million dollars per hour this year as we release some eight text
+files per month:  thus upping our productivity from $2 million.
+</para>
+
+<para>
+The Goal of Project Gutenberg is to Give Away One Trillion Etext
+Files by the December 31, 2001.  [10,000 x 100,000,000=Trillion]
+This is ten thousand titles each to one hundred million readers,
+which is 10% of the expected number of computer users by the end
+of the year 2001.
+</para>
+
+<para>
+We need your donations more than ever!
+</para>
+
+<para>
+All donations should be made to "Project Gutenberg/IBC", and are
+tax deductible to the extent allowable by law ("IBC" is Illinois
+Benedictine College).  (Subscriptions to our paper newsletter go
+to IBC, too)
+</para>
+
+<para>
+For these and other matters, please mail to:
+</para>
+
+<para>
+Project Gutenberg
+P. O. Box  2782
+Champaign, IL 61825
+</para>
+
+<para>
+When all other email fails try our Michael S. Hart, Executive
+Director:
+hart@vmd.cso.uiuc.edu (internet)   hart@uiucvmd   (bitnet)
+</para>
+
+<para>
+We would prefer to send you this information by email
+(Internet, Bitnet, Compuserve, ATTMAIL or MCImail).
+</para>
+
+<para>
+******
+If you have an FTP program (or emulator), please
+FTP directly to the Project Gutenberg archives:
+[Mac users, do NOT point and click. . .type]
+</para>
+
+<para>
+ftp uiarchive.cso.uiuc.edu
+login:  anonymous
+password:  your@login
+cd etext/etext90 through /etext96
+or cd etext/articles [get suggest gut for more information]
+dir [to see files]
+get or mget [to get files. . .set bin for zip files]
+GET INDEX?00.GUT
+for a list of books
+and
+GET NEW GUT for general information
+and
+MGET GUT* for newsletters.
+</para>
+
+<para>
+**Information prepared by the Project Gutenberg legal advisor**
+(Three Pages)
+</para>
+
+<para>
+***START**THE SMALL PRINT!**FOR PUBLIC DOMAIN ETEXTS**START***
+Why is this "Small Print!" statement here?  You know: lawyers.
+They tell us you might sue us if there is something wrong with
+your copy of this etext, even if you got it for free from
+someone other than us, and even if what's wrong is not our
+fault.  So, among other things, this "Small Print!" statement
+disclaims most of our liability to you.  It also tells you how
+you can distribute copies of this etext if you want to.
+</para>
+
+<para>
+*BEFORE!* YOU USE OR READ THIS ETEXT
+By using or reading any part of this PROJECT GUTENBERG-tm
+etext, you indicate that you understand, agree to and accept
+this "Small Print!" statement.  If you do not, you can receive
+a refund of the money (if any) you paid for this etext by
+sending a request within 30 days of receiving it to the person
+you got it from.  If you received this etext on a physical
+medium (such as a disk), you must return it with your request.
+</para>
+
+<para>
+ABOUT PROJECT GUTENBERG-TM ETEXTS
+This PROJECT GUTENBERG-tm etext, like most PROJECT GUTENBERG-
+tm etexts, is a "public domain" work distributed by Professor
+Michael S. Hart through the Project Gutenberg Association at
+Illinois Benedictine College (the "Project").  Among other
+things, this means that no one owns a United States copyright
+on or for this work, so the Project (and you!) can copy and
+distribute it in the United States without permission and
+without paying copyright royalties.  Special rules, set forth
+below, apply if you wish to copy and distribute this etext
+under the Project's "PROJECT GUTENBERG" trademark.
+</para>
+
+<para>
+To create these etexts, the Project expends considerable
+efforts to identify, transcribe and proofread public domain
+works.  Despite these efforts, the Project's etexts and any
+medium they may be on may contain "Defects".  Among other
+things, Defects may take the form of incomplete, inaccurate or
+corrupt data, transcription errors, a copyright or other
+intellectual property infringement, a defective or damaged
+disk or other etext medium, a computer virus, or computer
+codes that damage or cannot be read by your equipment.
+</para>
+
+<para>
+LIMITED WARRANTY; DISCLAIMER OF DAMAGES
+But for the "Right of Replacement or Refund" described below,
+[1] the Project (and any other party you may receive this
+etext from as a PROJECT GUTENBERG-tm etext) disclaims all
+liability to you for damages, costs and expenses, including
+legal fees, and [2] YOU HAVE NO REMEDIES FOR NEGLIGENCE OR
+UNDER STRICT LIABILITY, OR FOR BREACH OF WARRANTY OR CONTRACT,
+INCLUDING BUT NOT LIMITED TO INDIRECT, CONSEQUENTIAL, PUNITIVE
+OR INCIDENTAL DAMAGES, EVEN IF YOU GIVE NOTICE OF THE
+POSSIBILITY OF SUCH DAMAGES.
+</para>
+
+<para>
+If you discover a Defect in this etext within 90 days of
+receiving it, you can receive a refund of the money (if any)
+you paid for it by sending an explanatory note within that
+time to the person you received it from.  If you received it
+on a physical medium, you must return it with your note, and
+such person may choose to alternatively give you a replacement
+copy.  If you received it electronically, such person may
+choose to alternatively give you a second opportunity to
+receive it electronically.
+</para>
+
+<para>
+THIS ETEXT IS OTHERWISE PROVIDED TO YOU "AS-IS".  NO OTHER
+WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, ARE MADE TO YOU AS
+TO THE ETEXT OR ANY MEDIUM IT MAY BE ON, INCLUDING BUT NOT
+LIMITED TO WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
+PARTICULAR PURPOSE.
+</para>
+
+<para>
+Some states do not allow disclaimers of implied warranties or
+the exclusion or limitation of consequential damages, so the
+above disclaimers and exclusions may not apply to you, and you
+may have other legal rights.
+</para>
+
+<para>
+INDEMNITY
+You will indemnify and hold the Project, its directors,
+officers, members and agents harmless from all liability, cost
+and expense, including legal fees, that arise directly or
+indirectly from any of the following that you do or cause:
+[1] distribution of this etext, [2] alteration, modification,
+or addition to the etext, or [3] any Defect.
+</para>
+
+<para>
+DISTRIBUTION UNDER "PROJECT GUTENBERG-tm"
+You may distribute copies of this etext electronically, or by
+disk, book or any other medium if you either delete this
+"Small Print!" and all other references to Project Gutenberg,
+or:
+</para>
+
+<para>
+[1]  Only give exact copies of it.  Among other things, this
+     requires that you do not remove, alter or modify the
+     etext or this "small print!" statement.  You may however,
+     if you wish, distribute this etext in machine readable
+     binary, compressed, mark-up, or proprietary form,
+     including any form resulting from conversion by word pro-
+     cessing or hypertext software, but only so long as
+     *EITHER*:
+</para>
+
+<para>
+     [*]  The etext, when displayed, is clearly readable, and
+          does *not* contain characters other than those
+          intended by the author of the work, although tilde
+          (~), asterisk (*) and underline (_) characters may
+          be used to convey punctuation intended by the
+          author, and additional characters may be used to
+          indicate hypertext links; OR
+</para>
+
+<para>
+     [*]  The etext may be readily converted by the reader at
+          no expense into plain ASCII, EBCDIC or equivalent
+          form by the program that displays the etext (as is
+          the case, for instance, with most word processors);
+          OR
+</para>
+
+<para>
+     [*]  You provide, or agree to also provide on request at
+          no additional cost, fee or expense, a copy of the
+          etext in its original plain ASCII form (or in EBCDIC
+          or other equivalent proprietary form).
+</para>
+
+<para>
+[2]  Honor the etext refund and replacement provisions of this
+     "Small Print!" statement.
+</para>
+
+<para>
+[3]  Pay a trademark license fee to the Project of 20% of the
+     net profits you derive calculated using the method you
+     already use to calculate your applicable taxes.  If you
+     don't derive profits, no royalty is due.  Royalties are
+     payable to "Project Gutenberg Association / Illinois
+     Benedictine College" within the 60 days following each
+     date you prepare (or were legally required to prepare)
+     your annual (or equivalent periodic) tax return.
+</para>
+
+<para>
+WHAT IF YOU *WANT* TO SEND MONEY EVEN IF YOU DON'T HAVE TO?
+The Project gratefully accepts contributions in money, time,
+scanning machines, OCR software, public domain etexts, royalty
+free copyright licenses, and every other sort of contribution
+you can think of.  Money should be paid to "Project Gutenberg
+Association / Illinois Benedictine College".
+</para>
+
+<para>
+*END*THE SMALL PRINT! FOR PUBLIC DOMAIN ETEXTS*Ver.04.29.93*END*
+</para>
+</gutblurb>
+
+<markupblurb>
+Marked up by John Hanna Feb 2000
+Validated against gutbook1.dtd using MSXML Feb 2000
+Checked FB Feb 2000
+</markupblurb>
+
+<book>
+<acknowledge>A project of the HTML Writrs Guild and Project Gutenberg. Markup by an anonymous Project Gutenberg Volunteer, Markup by John Hanna Feb 2000</acknowledge>
+<frontmatter>
+<titlepage>
+<title>AN OCCURRENCE AT OWL CREEK BRIDGE</title>
+<para>by</para>
+<author>Ambrose Bierce</author>
+<para>
+THE MILLENNIUM FULCRUM EDITION, 1988
+</para>
+</titlepage>
+</frontmatter>
+<bookbody>
+<part>
+
+<chapter>
+<title>I</title>
+<para>
+A man stood upon a railroad bridge in northern Alabama,
+looking down into the swift water twenty feet below.  The
+man's hands were behind his back, the wrists bound with a
+cord.  A rope closely encircled his neck.  It was attached to
+a stout cross-timber above his head and the slack feel to the
+level of his knees.  Some loose boards laid upon the ties
+supporting the rails of the railway supplied a footing for
+him and his executioners -- two private soldiers of the
+Federal army, directed by a sergeant who in civil life may
+have been a deputy sheriff.  At a short remove upon the same
+temporary platform was an officer in the uniform of his rank,
+armed.  He was a captain.  A sentinel at each end of the
+bridge stood with his rifle in the position known as
+"support," that is to say, vertical in front of the left
+shoulder, the hammer resting on the forearm thrown straight
+across the chest -- a formal and unnatural position,
+enforcing an erect carriage of the body.  It did not appear
+to be the duty of these two men to know what was occurring at
+the center of the bridge; they merely blockaded the two ends
+of the foot planking that traversed it.
+</para>
+
+<para>
+Beyond one of the sentinels nobody was in sight; the railroad
+ran straight away into a forest for a hundred yards, then,
+curving, was lost to view.  Doubtless there was an outpost
+farther along.  The other bank of the stream was open ground
+-- a gentle slope topped with a stockade of vertical tree
+trunks, loopholed for rifles, with a single embrasure
+through which protruded the muzzle of a brass cannon
+commanding the bridge.  Midway up the slope between the
+bridge and fort were the spectators -- a single company of
+infantry in line, at "parade rest," the butts of their rifles
+on the ground, the barrels inclining slightly backward
+against the right shoulder, the hands crossed upon the stock.
+A lieutenant stood at the right of the line, the point
+of his sword upon the ground, his left hand resting upon his
+right.  Excepting the group of four at the center of the
+bridge, not a man moved.  The company faced the bridge,
+staring stonily, motionless.  The sentinels, facing the
+banks of the stream, might have been statues to adorn the
+bridge.  The captain stood with folded arms, silent,
+observing the work of his subordinates, but making no sign.
+Death is a dignitary who when he comes announced is to be
+received with formal manifestations of respect, even by those
+most familiar with him.  In the code of military etiquette
+silence and fixity are forms of deference.
+</para>
+
+<para>
+The man who was engaged in being hanged was apparently about
+thirty-five years of age.  He was a civilian, if one might
+judge from his habit, which was that of a planter.  His
+features were good -- a straight nose, firm mouth, broad
+forehead, from which his long, dark hair was combed straight
+back, falling behind his ears to the collar of his well
+fitting frock coat.  He wore a moustache and pointed beard,
+but no whiskers; his eyes were large and dark gray, and had a
+kindly expression which one would hardly have expected in one
+whose neck was in the hemp.  Evidently this was no vulgar
+assassin.  The liberal military code makes provision for
+hanging many kinds of persons, and gentlemen are not
+excluded.
+</para>
+
+<para>
+The preparations being complete, the two private soldiers
+stepped aside and each drew away the plank upon which he had
+been standing.  The sergeant turned to the captain, saluted
+and placed himself immediately behind that officer, who in
+turn moved apart one pace.  These movements left the
+condemned man and the sergeant standing on the two ends of
+the same plank, which spanned three of the cross-ties of the
+bridge.  The end upon which the civilian stood almost, but
+not quite, reached a fourth.  This plank had been held in
+place by the weight of the captain; it was now held by that
+of the sergeant.  At a signal from the former the latter
+would step aside, the plank would tilt and the condemned man
+go down between two ties.  The arrangement commended itself
+to his judgement as simple and effective.  His face had not
+been covered nor his eyes bandaged.  He looked a moment at
+his "unsteadfast footing," then let his gaze wander to the
+swirling water of the stream racing madly beneath his feet.
+A piece of dancing driftwood caught his attention and his
+eyes followed it down the current.  How slowly it appeared
+to move!  What a sluggish stream!
+</para>
+
+<para>
+He closed his eyes in order to fix his last thoughts upon his
+wife and children.  The water, touched to gold by the early
+sun, the brooding mists under the banks at some distance down
+the stream, the fort, the soldiers, the piece of drift -- all
+had distracted him.  And now he became conscious of a new
+disturbance.  Striking through the thought of his dear
+ones was sound which he could neither ignore nor understand,
+a sharp, distinct, metallic percussion like the stroke of a
+blacksmith's hammer upon the anvil; it had the same ringing
+quality.  He wondered what it was, and whether immeasurably
+distant or near by -- it seemed both.  Its recurrence was
+regular, but as slow as the tolling of a death knell.  He
+awaited each new stroke with impatience and -- he knew not
+why -- apprehension.  The intervals of silence grew
+progressively longer; the delays became maddening.  With
+their greater infrequency the sounds increased in strength
+and sharpness.  They hurt his ear like the trust of a knife;
+he feared he would shriek.  What he heard was the ticking of
+his watch.
+</para>
+
+<para>
+He unclosed his eyes and saw again the water below him.  "If
+I could free my hands," he thought, "I might throw off the
+noose and spring into the stream.  By diving I could evade
+the bullets and, swimming vigorously, reach the bank, take
+to the woods and get away home.  My home, thank God, is as
+yet outside their lines; my wife and little ones are still
+beyond the invader's farthest advance."
+</para>
+
+<para>
+As these thoughts, which have here to be set down in words,
+were flashed into the doomed man's brain rather than evolved
+from it the captain nodded to the sergeant.  The sergeant
+stepped aside.
+</para>
+</chapter>
+
+<chapter>
+<title>II</title>
+<para>
+Peyton Fahrquhar was a well to do planter, of an old and
+highly respected Alabama family.  Being a slave owner and
+like other slave owners a politician, he was naturally an
+original secessionist and ardently devoted to the Southern
+cause.  Circumstances of an imperious nature, which it is
+unnecessary to relate here, had prevented him from taking
+service with that gallant army which had fought the
+disastrous campaigns ending with the fall of Corinth, and he
+chafed under the inglorious restraint, longing for the
+release of his energies, the larger life of the soldier, the
+opportunity for distinction.  That opportunity, he felt,
+would come, as it comes to all in wartime.  Meanwhile he
+did what he could.  No service was too humble for him to
+perform in the aid of the South, no adventure to perilous for
+him to undertake if consistent with the character of a
+civilian who was at heart a soldier, and who in good faith
+and without too much qualification assented to at least a
+part of the frankly villainous dictum that all is fair in
+love and war.
+</para>
+
+<para>
+One evening while Fahrquhar and his wife were sitting on a
+rustic bench near the entrance to his grounds, a gray-clad
+soldier rode up to the gate and asked for a drink of water.
+Mrs. Fahrquhar was only too happy to serve him with her own
+white hands.  While she was fetching the water her husband
+approached the dusty horseman and inquired eagerly for news
+from the front.
+</para>
+
+<para>
+"The Yanks are repairing the railroads," said the man, "and
+are getting ready for another advance.  They have reached the
+Owl Creek bridge, put it in order and built a stockade on the
+north bank.  The commandant has issued an order, which is
+posted everywhere, declaring that any civilian caught
+interfering with the railroad, its bridges, tunnels, or
+trains will be summarily hanged.  I saw the order."
+</para>
+
+<para>
+"How far is it to the Owl Creek bridge?" Fahrquhar asked.
+</para>
+
+<para>
+"About thirty miles."
+</para>
+
+<para>
+"Is there no force on this side of the creek?"
+</para>
+
+<para>
+"Only a picket post half a mile out, on the railroad, and a
+single sentinel at this end of the bridge."
+</para>
+
+<para>
+"Suppose a man -- a civilian and student of hanging --
+should elude the picket post and perhaps get the better of
+the sentinel," said Fahrquhar, smiling, "what could he
+accomplish?"
+</para>
+
+<para>
+The soldier reflected.  "I was there a month ago," he
+replied.  "I observed that the flood of last winter had
+lodged a great quantity of driftwood against the wooden pier
+at this end of the bridge.  It is now dry and would burn like
+tinder."
+</para>
+
+<para>
+The lady had now brought the water, which the soldier drank.
+He thanked her ceremoniously, bowed to her husband and rode
+away.  An hour later, after nightfall, he repassed the
+plantation, going northward in the direction from which he
+had come.  He was a Federal scout.
+</para>
+</chapter>
+
+<chapter>
+<title>III</title>
+<para>
+ As Peyton Fahrquhar fell straight downward through the
+bridge he lost consciousness and was as one already dead.
+From this state he was awakened -- ages later, it seemed to
+him -- by the pain of a sharp pressure upon his throat,
+followed by a sense of suffocation.  Keen, poignant agonies
+seemed to shoot from his neck downward through every fiber of
+his body and limbs.  These pains appeared to flash along well
+defined lines of ramification and to beat with an
+inconceivably rapid periodicity.  They seemed like streams of
+pulsating fire heating him to an intolerable temperature.  As
+to his head, he was conscious of nothing but a feeling of
+fullness -- of congestion.  These sensations were
+unaccompanied by thought.  The intellectual part of his
+nature was already effaced; he had power only to feel, and
+feeling was torment.  He was conscious of motion.
+Encompassed in a luminous cloud, of which he was now merely
+the fiery heart, without material substance, he swung
+through unthinkable arcs of oscillation, like a vast
+pendulum.  Then all at once, with terrible suddenness, the
+light about him shot upward with the noise of a loud splash;
+a frightful roaring was in his ears, and all was cold and
+dark.  The power of thought was restored; he knew that the
+rope had broken and he had fallen into the stream.  There was
+no additional strangulation; the noose about his neck
+was already suffocating him and kept the water from his
+lungs.  To die of hanging at the bottom of a river! -- the
+idea seemed to him ludicrous.  He opened his eyes in the
+darkness and saw above him a gleam of light, but how distant,
+how inaccessible!  He was still sinking, for the light became
+fainter and fainter until it was a mere glimmer.  Then it
+began to grow and brighten, and he knew that he was rising
+toward the surface -- knew it with reluctance, for he was now
+very comfortable.  "To be hanged and drowned," he thought,
+"that is not so bad; but I do not wish to be shot.  No; I
+will not be shot; that is not fair."
+</para>
+
+<para>
+He was not conscious of an effort, but a sharp pain in his
+wrist apprised him that he was trying to free his hands.  He
+gave the struggle his attention, as an idler might observe
+the feat of a juggler, without interest in the outcome.  What
+splendid effort! -- what magnificent, what superhuman
+strength!  Ah, that was a fine endeavor!  Bravo!  The cord
+fell away; his arms parted and floated upward, the hands
+dimly seen on each side in the growing light.  He watched
+them with a new interest as first one and then the other
+pounced upon the noose at his neck.  They tore it away and
+thrust it fiercely aside, its undulations resembling those of
+a water snake.  "Put it back, put it back!"  He thought he
+shouted these words to his hands, for the undoing of the
+noose had been succeeded by the direst pang that he had yet
+experienced.  His neck ached horribly; his brain was on fire,
+his heart, which had been fluttering faintly, gave a great
+leap, trying to force itself out at his mouth.  His whole
+body was racked and wrenched with an insupportable anguish!
+But his disobedient hands gave no heed to the command.  They
+beat the water vigorously with quick, downward strokes,
+forcing him to the surface.  He felt his head emerge; his
+eyes were blinded by the sunlight; his chest expanded
+convulsively, and with a supreme and crowning agony his lungs
+engulfed a great draught of air, which instantly he expelled
+in a shriek!
+</para>
+
+<para>
+He was now in full possession of his physical senses.  They
+were, indeed, preternaturally keen and alert.  Something in
+the awful disturbance of his organic system had so exalted
+and refined them that they made record of things never before
+perceived.  He felt the ripples upon his face and heard their
+separate sounds as they struck.  He looked at the forest on
+the bank of the stream, saw the individual trees, the leaves
+and the veining of each leaf -- he saw the very insects upon
+them:  the locusts, the brilliant bodied flies, the gray
+spiders stretching their webs from twig to twig.  He noted
+the prismatic colors in all the dewdrops upon a million
+blades of grass.  The humming of the gnats that danced above
+the eddies of the stream, the beating of the dragon flies'
+wings, the strokes of the water spiders' legs, like oars
+which had lifted their boat -- all these made audible
+music.  A fish slid along beneath his eyes and he heard the
+rush of its body parting the water.
+</para>
+
+<para>
+He had come to the surface facing down the stream; in a
+moment the visible world seemed to wheel slowly round,
+himself the pivotal point, and he saw the bridge, the fort,
+the soldiers upon the bridge, the captain, the sergeant, the
+two privates, his executioners.  They were in silhouette
+against the blue sky.  They shouted and gesticulated,
+pointing at him.  The captain had drawn his pistol, but did
+not fire; the others were unarmed.  Their movements were
+grotesque and horrible, their forms gigantic.
+</para>
+
+<para>
+Suddenly he heard a sharp report and something struck the
+water smartly within a few inches of his head, spattering his
+face with spray.  He heard a second report, and saw one of
+the sentinels with his rifle at his shoulder, a light cloud
+of blue smoke rising from the muzzle.  The man in the water
+saw the eye of the man on the bridge gazing into his own
+through the sights of the rifle.  He observed that it was a
+gray eye and remembered having read that gray eyes were
+keenest, and that all famous marksmen had them.
+Nevertheless, this one had missed.
+</para>
+
+<para>
+A counter-swirl had caught Fahrquhar and turned him half
+round; he was again looking at the forest on the bank
+opposite the fort.  The sound of a clear, high voice in a
+monotonous singsong now rang out behind him and came across
+the water with a distinctness that pierced and subdued all
+other sounds, even the beating of the ripples in his ears.
+Although no soldier, he had frequented camps enough to know
+the dread significance of that deliberate, drawling,
+aspirated chant; the lieutenant on shore was taking a part in
+the morning's work.  How coldly and pitilessly -- with what
+an even, calm intonation, presaging, and enforcing
+tranquility in the men -- with what accurately measured
+interval fell those cruel words:
+</para>
+
+<para>
+"Company! . . . Attention!  . . . Shoulder arms! . . . Ready!
+. . . Aim!  . . . Fire!"
+</para>
+
+<para>
+Fahrquhar dived -- dived as deeply as he could.  The water
+roared in his ears like the voice of Niagara, yet he heard
+the dull thunder of the volley and, rising again toward the
+surface, met shining bits of metal, singularly flattened,
+oscillating slowly downward.  Some of them touched him on the
+face and hands, then fell away, continuing their descent.
+One lodged between his collar and neck; it was uncomfortably
+warm and he snatched it out.
+</para>
+
+<para>
+As he rose to the surface, gasping for breath, he saw that he
+had been a long time under water; he was perceptibly farther
+downstream -- nearer to safety.  The soldiers had almost
+finished reloading; the metal ramrods flashed all at once in
+the sunshine as they were drawn from the barrels,
+turned in the air, and thrust into their sockets.  The two
+sentinels fired again, independently and ineffectually.
+</para>
+
+<para>
+The hunted man saw all this over his shoulder; he was now
+swimming vigorously with the current.  His brain was as
+energetic as his arms and legs; he thought with the rapidity
+of lightning:
+</para>
+
+<para>
+"The officer," he reasoned, "will not make that martinet's
+error a second time.  It is as easy to dodge a volley as a
+single shot.  He has probably already given the command to
+fire at will.  God help me, I cannot dodge them all!"
+</para>
+
+<para>
+An appalling splash within two yards of him was followed by a
+loud, rushing sound, DIMINUENDO, which seemed to travel back
+through the air to the fort and died in an explosion which
+stirred the very river to its deeps!  A rising sheet of water
+curved over him, fell down upon him, blinded him, strangled
+him!  The cannon had taken an hand in the game.  As he shook
+his head free from the commotion of the smitten water he
+heard the deflected shot humming through the air ahead, and
+in an instant it was cracking and smashing the branches in
+the forest beyond.
+</para>
+
+<para>
+"They will not do that again," he thought; "the next time
+they will use a charge of grape.  I must keep my eye upon
+the gun; the smoke will apprise me -- the report arrives too
+late; it lags behind the missile.  That is a good gun."
+</para>
+
+<para>
+Suddenly he felt himself whirled round and round -- spinning
+like a top.  The water, the banks, the forests, the now
+distant bridge, fort and men, all were commingled and
+blurred.  Objects were represented by their colors only;
+circular horizontal streaks of color -- that was all he saw.
+He had been caught in a vortex and was being whirled on with
+a velocity of advance and gyration that made him giddy and
+sick.  In few moments he was flung upon the gravel at the
+foot of the left bank of the stream -- the southern bank --
+and behind a projecting point which concealed him from his
+enemies.  The sudden arrest of his motion, the abrasion of
+one of his hands on the gravel, restored him, and he wept
+with delight.  He dug his fingers into the sand, threw it
+over himself in handfuls and audibly blessed it.  It looked
+like diamonds, rubies, emeralds; he could think of nothing
+beautiful which it did not resemble.  The trees upon the bank
+were giant garden plants; he noted a definite order in their
+arrangement, inhaled the fragrance of their blooms.  A
+strange roseate light shone through the spaces among their
+trunks and the wind made in their branches the music of
+AEolian harps.  He had not wish to perfect his escape -- he
+was content to remain in that enchanting spot until retaken.
+</para>
+
+<para>
+A whiz and a rattle of grapeshot among the branches high
+above his head roused him from his dream.  The baffled
+cannoneer had fired him a random farewell.  He sprang
+to his feet, rushed up the sloping bank, and plunged into the
+forest.
+</para>
+
+<para>
+All that day he traveled, laying his course by the rounding
+sun.  The forest seemed interminable; nowhere did he
+discover a break in it, not even a woodman's road.  He had
+not known that he lived in so wild a region.  There was
+something uncanny in the revelation.
+</para>
+
+<para>
+By nightfall he was fatigued, footsore, famished.  The
+thought of his wife and children urged him on.  At last he
+found a road which led him in what he knew to be the right
+direction.  It was as wide and straight as a city street, yet
+it seemed untraveled.  No fields bordered it, no dwelling
+anywhere.  Not so much as the barking of a dog suggested
+human habitation.  The black bodies of the trees formed a
+straight wall on both sides, terminating on the horizon in a
+point, like a diagram in a lesson in perspective.  Overhead,
+as he looked up through this rift in the wood, shone great
+golden stars looking unfamiliar and grouped in strange
+constellations.  He was sure they were arranged in some order
+which had a secret and malign significance.  The wood on
+either side was full of singular noises, among which -- once,
+twice, and again -- he distinctly heard whispers in an
+unknown tongue.
+</para>
+
+<para>
+His neck was in pain and lifting his hand to it found it
+horribly swollen.  He knew that it had a circle of black
+where the rope had bruised it.  His eyes felt congested; he
+could no longer close them.  His tongue was swollen with
+thirst; he relieved its fever by thrusting it forward from
+between his teeth into the cold air.  How softly the turf had
+carpeted the untraveled avenue -- he could no longer feel the
+roadway beneath his feet!
+</para>
+
+<para>
+Doubtless, despite his suffering, he had fallen asleep while
+walking, for now he sees another scene -- perhaps he has
+merely recovered from a delirium.  He stands at the gate of
+his own home.  All is as he left it, and all bright and
+beautiful in the morning sunshine.  He must have traveled the
+entire night.  As he pushes open the gate and passes up the
+wide white walk, he sees a flutter of female garments; his
+wife, looking fresh and cool and sweet, steps down from the
+veranda to meet him.  At the bottom of the steps she stands
+waiting, with a smile of ineffable joy, an attitude of
+matchless grace and dignity.  Ah, how beautiful she is!  He
+springs forwards with extended arms.  As he is about to clasp
+her he feels a stunning blow upon the back of the neck; a
+blinding white light blazes all about him with a sound like
+the shock of a cannon -- then all is darkness and silence!
+</para>
+
+<para>
+Peyton Fahrquhar was dead; his body, with a broken neck,
+swung gently from side to side beneath the timbers of the
+Owl Creek bridge.
+</para>
+
+<para>
+End of The Project Gutenberg Etext of An Occurrence at Owl Creek Bridge
+</para>
+</chapter>
+</part>
+</bookbody>
+</book>
+</gutbook>
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/index/buildConfig.xml
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/index/buildConfig.xml	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/index/buildConfig.xml	(revision 14125)
@@ -0,0 +1,16 @@
+<buildConfig xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat" >
+  <metadataList>
+    <metadata name="numDocs">4</metadata>
+    <metadata name="buildType">lucene</metadata>
+  </metadataList>
+  <serviceRackList>
+    <serviceRack name="GutBookRetrieve">
+      <paramList>
+	<param name="tocXSLT" value="produce-toc"/>
+	<param name="documentEncoding" value="UTF-8"/>
+	<param name="documentRootTag" value="book"/>
+      </paramList>
+    </serviceRack>
+    <serviceRack name="LuceneSearch"/>
+  </serviceRackList>
+</buildConfig>
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/java/BuildXMLColl.java
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/java/BuildXMLColl.java	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/java/BuildXMLColl.java	(revision 14125)
@@ -0,0 +1,59 @@
+/**
+ *
+ * class for building a simple  XML collection 
+ * @author  kjdon@cs.waikato.ac.nz
+ * @version 
+ */
+
+
+import org.greenstone.gsdl3.util.GSFile;
+
+import java.io.File;
+
+public class BuildXMLColl {
+
+    public static void main (String args[]) throws Exception { 
+	if (args.length != 2) {
+	    System.out.println("Usage: java BuildXMLColl site-home coll-name");
+	    return;
+	}
+ 
+	String site_home = args[0];
+	String coll_name = args[1];
+
+	File import_dir = new File(GSFile.collectionImportDir(site_home, coll_name));
+	File building_dir = new File(GSFile.collectionBuildDir(site_home, coll_name));
+
+	if (!import_dir.exists()) {
+	    System.out.println("Couldn't find import dir for collection "+coll_name);
+	    return;
+	}
+
+	if (building_dir.exists()) {
+	    // get rid of it
+	    GSFile.deleteFile(building_dir);
+	}
+	building_dir.mkdir();
+	
+	File idx_dir = new File(building_dir.getPath()+File.separator+"idx"+File.separator+"temp.txt");
+	idx_dir = idx_dir.getParentFile();
+	File text_dir = new File(building_dir.getPath()+File.separator+"text"+File.separator+"temp.txt");
+	text_dir = text_dir.getParentFile();
+	idx_dir.mkdir();
+	text_dir.mkdir();
+	
+	// first we import the coll
+	ImportXML importer = new ImportXML();
+	importer.setOutDir(text_dir);
+	importer.init();
+	importer.importFile(import_dir);
+	importer.finish();
+	
+	// then we index it
+	IndexXML indexer = new IndexXML();
+	indexer.setOutDir(idx_dir);
+	indexer.init();
+	indexer.indexFile(text_dir);
+	indexer.finish();
+    }
+}
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/java/ImportXML.java
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/java/ImportXML.java	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/java/ImportXML.java	(revision 14125)
@@ -0,0 +1,116 @@
+/**
+ *
+ * @author  kjdon@cs.waikato.ac.nz
+ * @version 
+ */
+
+
+// gsdl3 classes
+import org.greenstone.gsdl3.util.XMLConverter;
+import org.greenstone.gsdl3.util.GSFile;
+// XML classes
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.traversal.NodeIterator;
+import org.w3c.dom.traversal.NodeFilter;
+import org.w3c.dom.traversal.DocumentTraversal;
+import org.apache.xml.serialize.XMLSerializer;
+import org.xml.sax.InputSource;
+import org.xml.sax.EntityResolver;
+// java classes
+import java.io.File;
+import java.io.FileOutputStream;
+
+public class ImportXML
+    implements EntityResolver {
+    File out_dir = null;
+    XMLConverter converter = null;
+
+    String base_path = null;
+    public ImportXML() {
+	converter = new XMLConverter();
+	converter.setEntityResolver(this);
+	
+    }
+    public void setOutDir(File out_dir) {
+	this.out_dir = out_dir;
+    }
+    public void init() {
+
+    }
+    public void importFile(File file) throws Exception {
+	importFile(file, "");
+    }
+    protected void importFile(File file, String local_path) throws Exception {
+
+	if (file.isDirectory()) {
+	    File files []  = file.listFiles();
+	    for (int i=0; i<files.length; i++) {
+		//if (files[i].getName().endsWith(".xml")) {
+		importFile(files[i], local_path+File.separator+files[i].getName());
+		    //}
+	    }
+	    return;
+	}
+
+	base_path = file.getPath();
+	base_path = base_path.substring(0, base_path.lastIndexOf(File.separatorChar));
+	System.out.println("base path = "+base_path);
+	// now we have an actual file
+	System.out.println("processing file "+file.getPath());
+	File out_file = new File (out_dir, local_path);
+	String name = file.getName();
+	if (name.endsWith(".dtd")) {
+	    if (!GSFile.copyFile(file, out_file)) {
+		System.err.println("couldn't copy dtd file "+file.getPath()+" to "+out_file.getPath()+"- please do the copy yourself");
+	    }
+	    //copy the file
+	    return;
+	}
+	if (!name.endsWith(".xml")) {
+	    // now we ignore any that don't end in .xml
+	    return;
+	}
+	// now do the importing
+	Document doc = converter.getDOM(file);
+	
+        String gs3NS = "http://www.greenstone.org/gs3";
+	
+        Element rootNode = doc.getDocumentElement();
+        
+        rootNode.setAttribute("xmlns:gs3", gs3NS);
+       
+        DocumentTraversal traversal = (DocumentTraversal)doc;
+        NodeIterator i = traversal.createNodeIterator(doc, NodeFilter.SHOW_ELEMENT, null, true);
+        
+        Element element = null;
+        Node node = null;
+        int id = 0;
+        while ((node = i.nextNode()) != null) {
+            element = (Element)node;
+	    if (XMLTagInfo.isIndexable(element.getNodeName())) {
+		element.setAttribute("gs3:id", Integer.toString(id++));
+	    }
+        }
+        
+        XMLSerializer gs3Serializer = new XMLSerializer(new FileOutputStream(out_file), null);
+        gs3Serializer.asDOMSerializer().serialize(doc);
+        
+    }
+
+    public void finish() {
+    }
+    
+    public InputSource resolveEntity (String public_id, String system_id) {
+	
+	if (system_id.startsWith("file://")) {
+	    return new InputSource(system_id);
+	}
+	if (!system_id.startsWith(File.separator)) {
+	    system_id = base_path+File.separatorChar+system_id;
+	}
+	return new InputSource("file://"+system_id);
+    }
+
+}
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/java/IndexXML.java
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/java/IndexXML.java	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/java/IndexXML.java	(revision 14125)
@@ -0,0 +1,43 @@
+
+/**
+ *
+ * @author  kjdon@cs.waikato.ac.nz
+ * @version 
+ */
+
+import java.io.File;
+
+public class IndexXML extends Object {
+
+    File out_dir = null;
+    Indexer indexer = null;
+    
+    public void setOutDir(File out_dir) {
+	this.out_dir = out_dir;
+    }
+
+    public void init() {
+	indexer = new Indexer(out_dir, true);
+    }
+    public void finish() {
+	indexer.finish();
+    }
+    public void indexFile(File file) {
+	
+	if (file.isDirectory()) {
+	    File[] files = file.listFiles();
+	    for (int i=0; i<files.length; i++) {
+		if (files[i].isDirectory() || files[i].getName().endsWith(".xml")) {
+		    indexFile(files[i]);
+		}
+	    }
+	    
+	} else {
+	    String name = file.getName();
+	    name = name.substring(0, name.lastIndexOf('.'));
+	    System.out.println("Indexing "+file.getPath()+" with id "+name);
+	    this.indexer.index(name, file);
+	}
+    }
+        
+}
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/java/Indexer.java
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/java/Indexer.java	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/java/Indexer.java	(revision 14125)
@@ -0,0 +1,202 @@
+import org.greenstone.gsdl3.util.GSEntityResolver;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+//import org.xml.sax.SAXParseException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+//import org.apache.lucene.document.DateField;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+//import org.apache.lucene.analysis.SimpleAnalyzer;
+
+import java.util.Stack;
+import java.io.FileInputStream;
+import java.io.File;
+import java.net.URL;
+
+
+
+public class Indexer extends DefaultHandler {
+    IndexWriter writer = null;
+    SAXParser sax_parser = null;
+    Stack stack = null;
+    String path = "";
+    String current_node = "";
+    String current_contents = "";
+    Document current_doc = null;
+    String scope = "";
+    protected String file_id = null;
+    private String base_path = null;
+    /** pass in true if want to create a new index, false if want to use the existing one */
+    public Indexer (File index_dir, boolean create) {
+	try {
+	    stack = new Stack();
+	    SAXParserFactory sax_factory = SAXParserFactory.newInstance();
+	    sax_parser = sax_factory.newSAXParser();
+	    writer = new IndexWriter(index_dir.getPath(), new StandardAnalyzer(), create);
+	    if (create) {
+		writer.optimize();
+	    }
+
+	} catch (Exception e) {
+
+	}
+    }
+
+    /** index one document */
+    public void index (String file_id, File file) {
+	this.file_id = file_id;
+	this.path = "";
+	this.base_path = file.getPath();
+	this.base_path = this.base_path.substring(0, this.base_path.lastIndexOf(File.separatorChar));
+	try {
+            sax_parser.parse(new InputSource(new FileInputStream(file)), this);
+        }
+        catch (Exception e) {
+	    println("parse error:");
+            e.printStackTrace();
+	}
+    }
+    
+    /** optimise the index */
+    public void finish() {
+	try {
+	    writer.optimize();
+	    writer.close();
+	} catch (Exception e) {}
+    }
+
+    protected void println(String s) { System.out.println(s); }
+
+    public void startDocument() throws SAXException {
+        println("Starting to index " + file_id);
+    }
+    public void endDocument() throws SAXException {
+        println("... indexing finished.");
+    }
+    public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
+	path = appendPathLink(path, qName, atts);
+	if (XMLTagInfo.isScopable(qName)) {
+	    scope = qName;
+	}
+	if (XMLTagInfo.isIndexable(qName)) {
+	    pushOnStack();
+	    current_node = qName;	
+	    System.out.println("going to index "+qName );
+	    String node_id = "";
+	    String id = "<"+qName;
+	    for (int i=0; i<atts.getLength(); i++) {
+		String name = atts.getQName(i);
+		String value = atts.getValue(i);
+		if (name!=null && value != null) {
+		    id += " "+name+"="+value;
+		}
+		if (name.equals("gs3:id")) {
+		    node_id = value;
+		}
+	    }
+	    id += "/>";
+
+	    if (scope.equals(qName)) {
+		current_doc.add(Field.UnIndexed("nodeID", this.file_id+"."+qName));
+	    } else {
+		current_doc.add(Field.UnIndexed("nodeID", this.file_id+"."+scope+"."+qName+"."+node_id));
+	    }
+	}
+    }
+    public void endElement(String uri, String localName, String qName) throws SAXException {
+	if (XMLTagInfo.isIndexable(qName) && qName.equals(current_node)) {
+	    current_doc.add(Field.UnStored("content", current_contents));
+	    try {
+		writer.addDocument(current_doc);
+	    } catch (java.io.IOException e) {
+		e.printStackTrace();
+	    }
+	    popOffStack();
+	}
+	
+	path = removePathLink(path);
+    }
+
+    public void characters(char ch[], int start, int length) throws SAXException {
+	String data = new String(ch, start, length).trim();
+	if (data.length() > 0 ) {
+	    current_contents += data;
+	}
+    }
+    
+    protected String appendPathLink(String path, String qName, Attributes atts) {
+
+	path = path + "/"+qName;
+	if (atts.getLength()>0) {
+	    String id = atts.getValue("gs3:id");
+	    if (id != null) {
+		path +=  "[@gs3:id='"+id+"']";
+	    }
+	}
+	return path;
+    }
+    protected String  removePathLink(String path) {
+
+	int i=path.lastIndexOf('/');
+	if (i==-1) {
+	    path="";
+	} else {
+	    path = path.substring(0, i);
+	}
+	return path;
+    }
+    /** these are what we save on the stack */
+    private class MyDocument {
+
+	public Document doc = null;
+	public String contents = null;
+	public String tagname = "";
+	
+    }
+    protected void pushOnStack() {
+	if (current_doc != null) {
+	    MyDocument save = new MyDocument();
+	    save.doc = current_doc;
+	    save.contents = current_contents;
+	    save.tagname = current_node;
+	    stack.push(save);
+	}
+	current_doc = new Document();
+	current_contents = "";
+	current_node = "";
+    }
+
+    protected void popOffStack() {
+	if (!stack.empty()) {
+	    MyDocument saved = (MyDocument)stack.pop();
+	    current_doc = saved.doc;
+	    current_contents = saved.contents;
+	    current_node = saved.tagname;
+	} else {
+	    current_doc = new Document();
+	    current_contents = "";
+	    current_node = "";
+	}
+    }
+
+    public InputSource resolveEntity (String public_id, String system_id) {
+	
+	if (system_id.startsWith("file://")) {
+	    return new InputSource(system_id);
+	}
+	if (!system_id.startsWith(File.separator)) {
+	    system_id = base_path+File.separatorChar+system_id;
+	}
+	return new InputSource("file://"+system_id);
+    }
+
+}
+
+
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/java/Search.java
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/java/Search.java	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/java/Search.java	(revision 14125)
@@ -0,0 +1,84 @@
+/*
+ * search.java
+ *
+ * Created on 25 February 2003, 02:25
+ */
+
+
+/**
+ *
+ * @author  kjdon@cs.waikato.ac.nz
+ * @version 
+ */
+
+import java.io.IOException;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.search.Searcher;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Hits;
+import org.apache.lucene.queryParser.QueryParser;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.index.Term;
+
+public class Search  {
+
+    public static void main (String args[]) {
+	
+	if (args.length == 0) {
+	    System.out.println("Usage: Search <index directory>");
+	    return;
+	}
+        try {
+	    Searcher searcher = new IndexSearcher(args[0]);
+	    Analyzer analyzer = new StandardAnalyzer();
+
+	    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+	    while (true) {
+		System.out.print("Query: ");
+		String line = in.readLine();
+		
+		if (line.length() == -1)
+		    break;
+		
+		Term term = new Term("content",line);
+		
+		Query query = new TermQuery(term);
+		System.out.println("Searching for: " + query.toString("content"));
+		
+		Hits hits = searcher.search(query);
+		System.out.println(hits.length() + " total matching documents");
+		
+		final int HITS_PER_PAGE=10;
+		
+		for (int start = 0; start < hits.length(); start += HITS_PER_PAGE) {
+		    int end = Math.min(hits.length(), start + HITS_PER_PAGE);
+		    for (int i = start; i < end; i++) {
+			Document doc = hits.doc(i);
+			String node_id= doc.get("nodeID");
+			System.out.println(i + ". ID: "+node_id);
+		    }
+		    
+		    if (hits.length() > end) {
+			System.out.print("more (y/n) ? ");
+			line = in.readLine();
+			if (line.length() == 0 || line.charAt(0) == 'n')
+			    break;
+		    }
+		}
+		
+	    }
+	    
+	    searcher.close();
+	}
+	catch (Exception e) {
+	    System.out.println(" caught a " + e.getClass() +
+			       "\n with message: " + e.getMessage());
+        }
+    }
+}
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/java/XMLTagInfo.java
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/java/XMLTagInfo.java	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/java/XMLTagInfo.java	(revision 14125)
@@ -0,0 +1,23 @@
+/** XMLTagInfo
+ * contains any methods that are specific to what kind of XML you are working on
+ */
+
+public class XMLTagInfo {
+
+    public static boolean isIndexable(String tag) {
+	if (tag.equals("chapter") || tag.equals("part") || tag.equals("frontmatter") || tag.equals("appendix") || tag.equals("index") || tag.equals("glossary") || tag.equals("biblio")) {
+	    return true;
+	} 
+	return false;
+    }
+
+    public static boolean isScopable(String tag) {
+
+	if (tag.equals("bookbody") || tag.equals("frontmatter") || tag.equals("backmatter")) {
+	    return true;
+	} 
+	return false;
+    }
+
+    
+}
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/resources/bookfrag.dtd
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/resources/bookfrag.dtd	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/resources/bookfrag.dtd	(revision 14125)
@@ -0,0 +1,529 @@
+<!--This is bookfrag DTD-->
+
+<!--entity declarations-->
+<!--#############################################-->
+
+<!ENTITY % stdatts 
+"ref   IDREF  #IMPLIED
+ id    ID     #IMPLIED
+ type  CDATA  #IMPLIED
+ role  CDATA  #IMPLIED
+ class CDATA  #IMPLIED"
+>
+
+<!ENTITY % inline.class "|quote|emph|ital|reference|date|place|name|graphic|txterr|mkuperr|misc ">
+
+<!ENTITY % block.class "|letter|blockquote|footnote|note|list|deflist|table|blockgraphic">
+
+
+<!-- the top level element-->
+<!--##############################################-->
+
+<!ELEMENT book (acknowledge?,meta*,frontmatter?,bookbody,backmatter?,endmeta*)>
+
+<!--begin top level element declarations-->
+<!--##############################################-->
+
+
+<!--the acknowledge element is for a simple statement 
+designed to be placed at the beginning of the visible document.
+Suggested content:
+  Name of Book
+  Author
+  PG and HWG blurb
+  Original Transcriber + date
+  Marker 
+  e.g.
+  "Origin of the Species by Charles Darwin
+  A project of Project Gutenberg and the HTML Writers Guild.
+  Transcribed by  
+  Markup by Frank Boumphrey. Jan 22 2000"
+  -->
+
+<!ELEMENT acknowledge (#PCDATA %inline.class;)*>
+<!ATTLIST acknowledge
+  %stdatts;
+>
+
+<!--the meta tags are here to provide a means for comment 
+at either the very beginning or end of the document-->
+<!ELEMENT meta EMPTY>
+<!ATTLIST meta
+   content  CDATA  #REQUIRED
+   id       ID     #IMPLIED
+>
+
+<!ELEMENT endmeta EMPTY >
+<!ATTLIST endmeta
+   content  CDATA  #REQUIRED
+   id       ID     #IMPLIED
+>
+
+
+
+<!--the bookbody element contains the body of the book it can 
+consist of either part or chapter divisions-->
+
+<!ELEMENT bookbody (part*|chapter*)>
+
+<!--
+the backmatter element contains the backmatter of the book -->
+
+<!ELEMENT backmatter ((appendix|index|glossary|biblio|note)*,colophon?)>
+
+<!--The endmeta tag is groupedwith its twin meta-->
+
+
+<!--end top level element declarations-->
+
+<!--begin frontmatter element declarations-->
+<!--##############################################-->
+
+<!ELEMENT frontmatter (htitlepage|copypage|epigraph|titlepage|
+                toc|acksect|dedication|preface|introduction|miscfm)*>
+
+<!ELEMENT htitlepage (#PCDATA|title|subtitle|author|para|poem|song %inline.class;)*>
+<!ATTLIST htitlepage
+  %stdatts;
+>
+
+<!ELEMENT copypage (#PCDATA|para|poem|song|note %inline.class;)*>
+<!ATTLIST copypage
+  %stdatts;
+>
+
+<!ELEMENT epigraph (#PCDATA|para|poem|song|note|blockquote %inline.class;)*>
+<!ATTLIST epigraph
+  %stdatts;
+>
+
+
+<!ELEMENT titlepage (#PCDATA|partnum|title|subtitle|author|pubinfo|para|poem|song|note|line %inline.class;)*>
+<!ATTLIST titlepage
+  %stdatts;
+>
+
+<!ELEMENT pubinfo (#PCDATA|para|line %inline.class;)*>
+<!ATTLIST pubinfo
+  %stdatts;
+>
+
+
+<!ELEMENT toc (#PCDATA|title|subtitle|subsubtitle|item|list|deflist %inline.class;)*>
+<!--use type or role to describe toctype="other"-->
+<!ATTLIST toc
+  toctype (contents|maps|graphics|tables|other) "contents" 
+  %stdatts;
+>
+
+<!ELEMENT acksect (#PCDATA|para|poem|song|note %inline.class;)*>
+<!ATTLIST acksect
+  %stdatts;
+>
+
+<!ELEMENT dedication (#PCDATA|title|para|poem|song|note %inline.class;)*>
+<!ATTLIST dedication
+  %stdatts;
+>
+
+
+<!ELEMENT preface ((title|chapheader)?,(para|poem|song|sect1|simplesect %block.class;)*,endchap?,preauthor?)>
+<!ATTLIST preface  %stdatts;
+>
+
+<!ELEMENT introduction ((title|chapheader)?,(para|poem|song|sect1|simplesect %block.class;)*,endchap?)>
+<!ATTLIST introduction  %stdatts;
+>
+
+<!ELEMENT miscfm (#PCDATA|para|poem|song|note %inline.class;)*>
+<!ATTLIST miscfm
+  %stdatts;
+>
+
+<!ELEMENT preauthor (#PCDATA|author %inline.class;)*>
+<!ATTLIST preauthor
+  %stdatts;
+>
+
+
+
+<!--end frontmatter element declarations-->
+
+<!--begin bookbody element declarations-->
+<!--##############################################-->
+
+
+<!ELEMENT part (acknowledge?,(titlepage|toc|htitlepage)*,chapter*)>
+<!ATTLIST part
+  %stdatts;
+>
+
+<!ELEMENT chapter ((title|chapheader)?,(para|poem|song|sect1|simplesect|page %block.class;)*,endchap?)>
+<!ATTLIST chapter  %stdatts;
+>
+
+<!--end bookbody element declarations-->
+
+<!--the lowerlevel bookbody elements-->
+<!--##############################################-->
+
+<!--the chapter heading elements-->
+<!--##############################################-->
+
+
+
+
+<!ELEMENT title (#PCDATA %inline.class;)*>
+<!ATTLIST title
+  %stdatts;
+>
+
+<!ELEMENT subtitle (#PCDATA %inline.class;)*>
+<!ATTLIST subtitle
+  %stdatts;
+>
+
+<!ELEMENT subsubtitle (#PCDATA %inline.class;)*>
+<!ATTLIST subsubtitle
+  %stdatts;
+>
+
+
+
+<!--validity constraint. Only one title,chapnum and chapsummary -->
+<!ELEMENT chapheader (title|subtitle|chapnum|chapsummary|blockquote|para|note)*>
+<!ATTLIST chapheader
+  %stdatts;
+>
+
+
+<!ELEMENT chapnum (#PCDATA %inline.class;)*>
+<!ATTLIST chapnum
+  %stdatts;
+>
+
+<!ELEMENT chapsummary (#PCDATA %inline.class;)*>
+<!ATTLIST chapsummary
+  %stdatts;
+>
+
+
+<!--begin backmatter element declarations-->
+<!--##############################################-->
+
+<!--end backmatter element declarations-->
+
+<!ELEMENT index (title|item|list|deflist|note)*>
+<!ATTLIST index
+  indtype (contents|authors|firstlines|tables|other) "contents" 
+  %stdatts;
+>
+
+<!ELEMENT glossary (title|item|list|deflist|note)*>
+<!ATTLIST glossary  
+  %stdatts;
+>
+
+<!ELEMENT biblio (title|item|list|deflist|note)*>
+<!ATTLIST biblio  
+  %stdatts;
+>
+
+
+<!ELEMENT appendix ((title|chapheader)?,(para|poem|song|sect1|simplesect %block.class;)*,endchap?)>
+<!ATTLIST appendix  %stdatts;
+>
+
+<!ELEMENT colophon (#PCDATA|para|poem|song %inline.class;)*>
+<!ATTLIST colophon
+  %stdatts;
+>
+
+<!--the block elements-->
+<!--##############################################-->
+
+
+<!--validity constraint. Only one title per paragraph-->
+<!ELEMENT para (#PCDATA|title %inline.class;)*>
+<!ATTLIST para
+  %stdatts;
+>
+
+<!ELEMENT simplesect (title,(subtitle|para|poem|song %block.class;)*)>
+<!ATTLIST simplesect
+  %stdatts;
+>
+
+<!ELEMENT sect1 (title,(sect2|simplesect|para|poem|song %block.class;)*)>
+<!ATTLIST sect1
+  %stdatts;
+>
+
+<!ELEMENT sect2 (title,(sect3|simplesect|subtitle|para|poem|song  %block.class;)*)>
+<!ATTLIST sect2
+  %stdatts;
+>
+
+<!ELEMENT sect3 (title,(sect4|simplesect|subtitle|para|poem|song  %block.class;)*)>
+<!ATTLIST sect3
+  %stdatts;
+>
+
+<!ELEMENT sect4 (title,(simplesect|subtitle|para|poem|song  %block.class;)*)>
+<!ATTLIST sect4
+  %stdatts;
+>
+
+<!ELEMENT page (#PCDATA %inline.class;)*>
+<!ATTLIST page
+  %stdatts;
+>
+
+<!ELEMENT misc (#PCDATA %inline.class;)*>
+<!ATTLIST misc
+  %stdatts;
+>
+
+
+
+<!ELEMENT blockquote (title?,(para|poem|song)*,attrib?)>
+<!ATTLIST blockquote
+  %stdatts;
+>
+
+<!ELEMENT attrib (#PCDATA %inline.class;)*>
+<!ATTLIST attrib
+  %stdatts;
+>
+
+<!ELEMENT caption (#PCDATA %inline.class;)*>
+<!ATTLIST caption
+  %stdatts;
+>
+<!--##############################################-->
+<!--poetry and songs in the text-->
+<!ELEMENT poem (#PCDATA|title|subtitle|verse|line|note|footnote %inline.class;)*>
+<!ATTLIST poem
+  %stdatts;
+>
+
+<!ELEMENT song (#PCDATA|title|subtitle|verse|line|note|footnote %inline.class;)*>
+<!ATTLIST song
+  %stdatts;
+>
+
+
+<!ELEMENT verse (title|subtitle|line|note)*>
+<!ATTLIST verse
+  %stdatts;
+>
+
+<!ELEMENT line (#PCDATA %inline.class;)*>
+<!ATTLIST line
+  %stdatts;
+>
+
+
+<!--validity constraint: Only one title per poem or per verse-->
+
+<!--end of poetry in the text-->
+
+<!--letter module-->
+
+<!ELEMENT letter (address|to|from|salut|sig|title|subtitle|para|poem|song|line|note)*>
+<!ATTLIST letter
+  %stdatts;
+>
+
+<!ELEMENT address (#PCDATA|para|line %inline.class;)*>
+<!ATTLIST address
+  %stdatts;
+>
+
+<!ELEMENT to (#PCDATA|para|line %inline.class;)*>
+<!ATTLIST to
+  %stdatts;
+>
+
+
+<!ELEMENT from (#PCDATA|para|line %inline.class;)*>
+<!ATTLIST from
+  %stdatts;
+>
+
+
+<!ELEMENT salut (#PCDATA|para|line %inline.class;)*>
+<!ATTLIST salut
+  %stdatts;
+>
+
+
+<!ELEMENT sig (#PCDATA|para|line %inline.class;)*>
+<!ATTLIST sig
+  %stdatts;
+>
+
+
+<!--end letters module-->
+<!--endchap-->
+<!--##############################################-->
+<!--
+  Endchap should only be used when there is a 
+  considerable ammount of material to be organized.
+  For the occasional note footnote and note will suffice
+-->
+
+<!ELEMENT endchap (para %block.class;)*>
+<!ATTLIST endchap  %stdatts;
+>
+
+<!--lists-->
+<!--##############################################-->
+
+
+<!ELEMENT list (title?,(list|item)*)>
+<!ATTLIST list
+  %stdatts;
+>
+
+<!ELEMENT item (#PCDATA|para|poem|song|simplesect %block.class; %inline.class;)*>
+<!ATTLIST item
+  %stdatts;
+>
+
+<!ELEMENT deflist (title?,(item,desc?,def*)*)>
+<!ATTLIST deflist
+  %stdatts;
+>
+
+<!ELEMENT desc (#PCDATA %inline.class;)*>
+<!ATTLIST desc
+  %stdatts;
+>
+
+<!ELEMENT def (#PCDATA %inline.class;)*>
+<!ATTLIST def
+  %stdatts;
+>
+<!--end lists-->
+<!--table element-->
+<!--##############################################-->
+
+
+<!ELEMENT table (title?,row*,caption?)>
+<!ATTLIST table
+  %stdatts;
+>
+
+<!ELEMENT row (cell)*>
+<!ATTLIST row
+  %stdatts;
+>
+
+<!ELEMENT cell (#PCDATA %block.class; %inline.class;)*>
+<!ATTLIST cell
+  %stdatts;
+>
+
+<!--end table-->
+
+<!--graphics-->
+<!--##############################################-->
+
+<!--
+  Note that the required desc attribute is added 
+  text composed by the marker.
+-->
+
+<!ELEMENT graphic EMPTY >
+<!ATTLIST graphic
+  desc CDATA #REQUIRED
+  href CDATA #REQUIRED
+  %stdatts;
+>
+
+<!ELEMENT blockgraphic (title?,graphic,caption?)>
+<!ATTLIST blockgraphic
+  %stdatts;
+>
+
+
+<!--the inline elements-->
+<!--##############################################-->
+
+
+
+<!ELEMENT footnote (#PCDATA %inline.class;)*>
+<!ATTLIST footnote
+  %stdatts;
+>
+
+<!ELEMENT note (#PCDATA %inline.class;)*>
+<!ATTLIST note
+  %stdatts;
+>
+
+
+<!ELEMENT quote (#PCDATA %inline.class;)*>
+<!ATTLIST quote
+  %stdatts;
+>
+
+<!ELEMENT emph (#PCDATA %inline.class;)*>
+<!ATTLIST emph
+  %stdatts;
+>
+
+<!ELEMENT ital (#PCDATA %inline.class;)*>
+<!ATTLIST ital
+  %stdatts;
+>
+
+<!ELEMENT reference (#PCDATA %inline.class;)*>
+<!ATTLIST reference
+  %stdatts;
+>
+
+<!ELEMENT author (#PCDATA %inline.class;)*>
+<!ATTLIST author
+  %stdatts;
+>
+
+<!ELEMENT date (#PCDATA %inline.class;)*>
+<!ATTLIST date
+  %stdatts;
+>
+
+<!ELEMENT place (#PCDATA %inline.class;)*>
+<!ATTLIST place
+  %stdatts;
+>
+
+<!ELEMENT name (#PCDATA %inline.class;)*>
+<!ATTLIST name
+  %stdatts;
+>
+
+
+<!--use to enclose the text you think is in error
+optional explanation if error is not obvious-->
+<!ELEMENT txterr (#PCDATA)*>
+<!ATTLIST txterr
+  explain  CDATA  #IMPLIED
+  %stdatts;
+>
+
+<!--an explanation is required-->
+<!ELEMENT mkuperr EMPTY>
+<!ATTLIST mkuperr
+  explain  CDATA  #REQUIRED
+  %stdatts;
+>
+
+<!--added as titlepage content  Feb/6/00-->
+<!ELEMENT partnum (#PCDATA %inline.class;)*>
+<!ATTLIST partnum
+  %stdatts;
+>
+
+<!--End of bookfrag dtd-->
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/resources/gutbook1.dtd
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/resources/gutbook1.dtd	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/resources/gutbook1.dtd	(revision 14125)
@@ -0,0 +1,40 @@
+<!--
+GUTBOOK DTD V 1.0
+==================
+
+GENERAL NOTES
++++++++++++++
+This is gutbook dtd version 1.0
+file name is gutpoems1.dtd
+This dtd is a first pass at a dtd for marking up 
+books for project gutenberg.
+It was originally developed for marking up the Darwins books.
+
+REVISION HISTORY
+++++++++++++++++
+Original Author
+Frank Boumphrey  1/19/2000
+
+COPYRIGHT NOTICE
+++++++++++++++++
+This DTD is the copyright of the HTML writers guild.
+Permission is given in perpetuity for any one to use 
+this DTD provided that these notes and this  copyright 
+notice is included.
+
+
+-->
+
+<!--Begin gutbook DTD-->
+<!ELEMENT gutbook (gutblurb,markupblurb,book*,endmarkupblurb?,endgutblurb?)>
+
+<!ELEMENT gutblurb (#PCDATA|para|simplesect|title)*>
+<!ELEMENT markupblurb (#PCDATA|para|simplesect|title)*>
+<!ELEMENT endmarkupblurb (#PCDATA|para|simplesect|title)*>
+<!ELEMENT endgutblurb (#PCDATA|para|simplesect|title)*>
+
+<!--Include bookfrag.dtd-->
+
+<!ENTITY % bookfrag SYSTEM "bookfrag.dtd">
+%bookfrag;
+<!--end of file-->
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/transform/about.xsl
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/transform/about.xsl	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/transform/about.xsl	(revision 14125)
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+
+  <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+
+  <xsl:output method="html"/>  
+
+  <xsl:template name="pageTitle">
+    Sample XML Texts Collection
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+  <xsl:template match="pageResponse">
+    <xsl:apply-templates select="collection"/>
+  </xsl:template>
+
+  <xsl:template match="collection">
+    <xsl:variable name="collName" select="@name"/>
+    <xsl:call-template name="standardPageBanner">
+      <xsl:with-param name="collName" select="$collName"/>
+      <xsl:with-param name="pageType">about</xsl:with-param>
+    </xsl:call-template>
+    <xsl:call-template name="navigationBar">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>      
+    <p/><xsl:value-of select="displayItem[@name='description']" disable-output-escaping='yes'/>
+    <p/><xsl:apply-templates select="documentList">
+      <xsl:with-param name="collName" select="@name"/>
+    </xsl:apply-templates>
+  </xsl:template>
+  
+  <xsl:template match="documentList">
+    <xsl:param name="collName"/>
+    <ul>
+      <xsl:for-each select="document">
+	<li><a href="{$library_name}?a=xd&amp;sa=toc&amp;sc=full&amp;c={$collName}&amp;d={@name}"><xsl:value-of select="metadataList/metadata[@name='Title']"/></a></li>
+      </xsl:for-each>
+    </ul>
+  </xsl:template>
+</xsl:stylesheet>
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/transform/darwin.css
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/transform/darwin.css	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/transform/darwin.css	(revision 14125)
@@ -0,0 +1,342 @@
+/*This is darwin.css*/
+
+ gutblurb{
+  display:none;
+ }
+
+ markupblurb
+  {
+  display:none;
+
+  }
+ endgutblurb{
+  display:none;
+ }
+
+ para,sect1,sect2,sect3,sect4,simplesect{
+  display:block;
+  }
+
+
+ title1,item,chapter,chapnum,chapsummary,desc,def,letter
+{
+  display:block;
+  }
+
+ blockquote,footnote,note,list,deflist,blockgraphic{
+  display:block;
+  }
+
+ quote,emph,ital,reference,date,place,name,graphic,misc{
+  display:inline;
+  }
+
+  acknowledge{
+  display:block;
+  text-align:center;
+  font-size:8pt;
+  font-family:arial,sans-serif;
+  margin-top:8pt;
+  margin-bottom:12pt;
+  }
+
+ htitlepage title1{
+  display:block;
+  text-align:center;
+  font-size:16pt;
+  font-family:arial,sans-serif;
+  margin-top:8pt;
+  margin-bottom:12pt;
+  }
+
+ htitlepage subtitle{
+  display:block;
+  text-align:center;
+  font-size:14pt;
+  font-family:arial,sans-serif;
+  margin-top:8pt;
+  margin-bottom:12pt;
+  }
+
+  htitlepage author{
+  display:block;
+  text-align:center;
+  font-size:14pt;
+  font-family:arial,sans-serif;
+  margin-top:8pt;
+  margin-bottom:12pt;
+  }
+
+  epigraph{
+  display:block;
+  text-align:center;
+  font-size:12pt;
+  margin-top:8pt;
+  margin-bottom:12pt;
+  }
+
+
+  epigraph blockquote{
+  display:block;
+  text-align:left;
+  font-size:12pt;
+  margin-top:8pt;
+  margin-left:24pt;
+  margin-right:24pt;
+  margin-bottom:12pt;
+  }
+
+  epigraph attrib{
+  display:block;
+  text-align:left;
+  font-size:12pt;
+  margin-top:8pt;
+  margin-right:24pt;
+  margin-left:24pt;
+  margin-bottom:12pt;
+  }
+
+ titlepage title1{
+  display:block;
+  text-align:center;
+  font-size:16pt;
+  font-family:arial,sans-serif;
+  margin-top:8pt;
+  margin-bottom:12pt;
+  }
+
+  titlepage para{
+  display:block;
+  text-align:center;
+  font-size:12pt;
+  font-family:arial,sans-serif;
+  margin-top:8pt;
+  margin-bottom:12pt;
+  }
+
+  titlepage line{
+  display:block;
+  text-align:center;
+  font-size:12pt;
+  font-family:arial,sans-serif;
+  margin-top:8pt;
+  margin-bottom:12pt;
+  }
+
+  titlepage subtitle{
+  display:block;
+  text-align:center;
+  font-size:14pt;
+  font-family:arial,sans-serif;
+  margin-top:8pt;
+  margin-bottom:12pt;
+  }
+
+
+
+  titlepage author{
+  display:block;
+  text-align:center;
+  font-size:14pt;
+  font-family:arial,sans-serif;
+  margin-top:8pt;
+  margin-bottom:12pt;
+  }
+
+ titlepage partnum{
+  display:block;
+  text-align:center;
+  font-size:16pt;
+  font-family:arial,sans-serif;
+  margin-top:8pt;
+  margin-bottom:12pt;
+  }
+
+ dedication title1{
+  display:block;
+  text-align:center;
+  font-size:16pt;
+  font-family:arial,sans-serif;
+  margin-top:8pt;
+  margin-bottom:12pt;
+  }
+
+  toc title1{
+  display:block;
+  text-align:left;
+  font-size:14pt;
+  font-family:arial,sans-serif;
+  margin-top:12pt;
+  margin-left:24pt;
+  margin-bottom:12pt;
+  }
+
+  toc subtitle{
+  display:block;
+  text-align:left;
+  font-weight:bold;
+  font-size:13pt;
+  font-family:arial,sans-serif;
+  margin-top:12pt;
+  margin-left:24pt;
+  margin-bottom:12pt;
+  }
+
+
+  toc item{
+  display:block;
+  text-align:left;
+  font-size:12pt;
+  font-family:arial,sans-serif;
+  margin-top:12pt;
+  margin-left:36pt;
+  margin-bottom:12pt;
+  }
+
+
+  toc def{
+  display:block;
+  text-align:left;
+  font-size:12pt;
+  font-family:times new roman,serif;
+  margin-top:12pt;
+  margin-left:48pt;
+  margin-right:24pt;
+
+  margin-bottom:12pt;
+  }
+
+  toc desc{
+  display:block;
+  text-align:left;
+  font-size:10pt;
+  font-family:arial,sans-serif;
+  margin-top:12pt;
+  margin-left:42pt;
+  margin-bottom:12pt;
+  }
+
+ preface title1{
+  display:block;
+  text-align:left;
+  font-size:14pt;
+  font-family:arial,sans-serif;
+  margin-top:12pt;
+  margin-left:12pt;
+  margin-bottom:12pt;
+  }
+
+  introduction title1{
+  display:block;
+  text-align:left;
+  font-size:14pt;
+  font-family:arial,sans-serif;
+  margin-top:12pt;
+  margin-left:12pt;
+  margin-bottom:12pt;
+  }
+
+  salut,sig,para{
+  display:block;
+  text-align:left;
+  font-size:12pt;
+  font-family:times new roman,serif;
+  margin-top:12pt;
+  margin-left:24pt;
+  margin-right:24pt;
+  margin-bottom:12pt;
+  }
+
+  poem{
+  display:block;
+  text-align:left;
+  font-size:12pt;
+  margin-left:24pt;
+  margin-top:18pt;
+  margin-bottom:18pt;
+  }
+
+  line{
+  display:block;
+  text-align:left;
+  font-size:12pt;
+  margin-left:24pt;
+  margin-right:24pt;
+  }
+
+  chapter title1{
+  display:block;
+  text-align:left;
+  font-size:14pt;
+  font-family:arial,sans-serif;
+  margin-top:12pt;
+  margin-left:12pt;
+  margin-bottom:12pt;
+  }
+
+  chapter chapnum{
+  display:block;
+  text-align:center;
+  font-size:14pt;
+  font-family:arial,sans-serif;
+  margin-top:12pt;
+  margin-bottom:12pt;
+  }
+
+  chapter chapsummary{
+  display:block;
+  text-align:left;
+  font-size:12pt;
+  font-style:italic;
+  font-family:times new roman,serif;
+  margin-top:12pt;
+  margin-left:48pt;
+  margin-right:36pt;
+  margin-bottom:12pt;
+  }
+
+  chapter blockquote para{
+  display:block;
+  text-align:left;
+  font-size:11pt;
+  
+  margin-top:8pt;
+  margin-left:48pt;
+  margin-right:48pt;
+  margin-bottom:12pt;
+  }
+
+
+  index item{
+  display:block;
+  text-align:left;
+  font-size:12pt;
+  font-family:times new roman,serif;
+  margin-top:8pt;
+  margin-left:12pt;
+  margin-bottom:8pt;
+  }
+
+  index title1{
+  display:block;
+  text-align:left;
+  font-size:14pt;
+  font-family:arial,sans-serif;
+  margin-top:12pt;
+  margin-left:12pt;
+  margin-bottom:12pt;
+  }
+
+  list item{
+  color:black;
+  display:block;
+  text-align:left;
+  font-size:12pt;
+  font-family:times new roman,serif;
+  margin-top:8pt;
+  margin-left:48pt;
+  margin-bottom:8pt;
+  }
+
+
+
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/transform/document-content.xsl
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/transform/document-content.xsl	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/transform/document-content.xsl	(revision 14125)
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+
+  <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+
+  <xsl:output method="html"/> 
+  
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="/page/pageResponse/documentNode/metadataList/metadata[@name='root_Title']"/>
+  </xsl:template>
+  
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle">
+    <link type="text/css" href="sites/localsite/collect/gberg/transform/darwin.css" rel="stylesheet"/>
+  </xsl:template>
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName"><xsl:value-of select="/page/pageRequest/paramList/param[@name='c']/@value"/></xsl:variable>
+    <xsl:call-template name="standardPageBanner">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+    <xsl:call-template name="navigationBar">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>      
+    <!-- display the document -->
+    <xsl:apply-templates select="documentNode">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:apply-templates>
+    <xsl:call-template name="dividerBar"/>
+  </xsl:template>
+
+  <xsl:template match="documentNode">
+    <xsl:param name="collName"/>
+    <xsl:variable name="docname"><xsl:choose><xsl:when test="contains(@nodeID, '.')"><xsl:value-of select="substring-before(@nodeID, '.')"/></xsl:when><xsl:otherwise><xsl:value-of select="@nodeID"/></xsl:otherwise></xsl:choose></xsl:variable>
+    <h1>
+      <center>
+	<a href="{$library_name}?a=xd&amp;sa=toc&amp;c={$collName}&amp;d={$docname}"><xsl:attribute name="title">Go to the document contents</xsl:attribute><xsl:value-of select="metadataList/metadata[@name='root_Title']"/>&#160;</a>
+      </center>
+    </h1>
+    <xsl:apply-templates select="nodeContent/*"/>
+  </xsl:template>
+
+  <xsl:template match="gutblurb | markupblurb | endmarkupblurb | endgutblurb">
+  </xsl:template>
+
+  <xsl:template match="gutbook | book | frontmatter | bookbody | backmatter | titlepage| htitlepage | toc | dedication | preface | introduction | chapter |  part | chapheader | index | appendix | glossary">
+    <xsl:copy>
+      <xsl:copy-of select="@*"/>
+      <xsl:apply-templates/>
+    </xsl:copy>
+  </xsl:template>
+
+<!-- dont seem to be able to apply styles to title tags - cos they are special to html. so we rename title to title1-->
+  <xsl:template match="title">
+    <title1>
+      <xsl:apply-templates/>
+    </title1>
+  </xsl:template>  
+    
+  <xsl:template match="*">
+    <xsl:copy-of select="."/>
+  </xsl:template>
+
+  <xsl:template match="metadataList">
+  </xsl:template>
+
+</xsl:stylesheet>
+
+
+
+
+
+
+
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/transform/document-toc.xsl
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/transform/document-toc.xsl	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/transform/document-toc.xsl	(revision 14125)
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:gs3="http://www.greenstone.org/gs3"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+
+  <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+
+  <xsl:output method="html"/> 
+  
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="/page/pageResponse/documentNode/metadataList/metadata[@name='root_Title']"/>: Table of Contents
+  </xsl:template>
+  
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+  
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName"><xsl:value-of select="/page/pageRequest/paramList/param[@name='c']/@value"/></xsl:variable>
+    <xsl:call-template name="standardPageBanner">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+    <xsl:call-template name="navigationBar">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>      
+    <!-- display the document -->
+    <xsl:apply-templates select="documentNode">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:apply-templates>
+    <xsl:call-template name="dividerBar"/>
+  </xsl:template>
+
+  <xsl:template match="documentNode">
+    <xsl:param name="collName"/>
+    <xsl:variable name="docname"><xsl:choose><xsl:when test="contains(@nodeID, '.')"><xsl:value-of select="substring-before(@nodeID, '.')"/></xsl:when><xsl:otherwise><xsl:value-of select="@nodeID"/></xsl:otherwise></xsl:choose></xsl:variable>
+    <h1>
+      <center>
+	<xsl:value-of select="metadataList/metadata[@name='root_Title']"/>
+      </center>
+    </h1>
+    <xsl:apply-templates select="nodeStructure/gutbook/book"><xsl:with-param name="collName" select="$collName"/><xsl:with-param name="docName" select="$docname"/></xsl:apply-templates>
+  </xsl:template>
+  
+  <xsl:template match="book">
+    <xsl:param name="collName"/>
+    <xsl:param name="docName"/>
+    <h1>
+      Contents
+    </h1>
+    <ul class="toc">
+      <xsl:if test="acknowledge">
+	<li class='toc'>
+	  <a href="{$library_name}?a=xd&amp;sa=text&amp;d={$docName}.acknowledge&amp;c={$collName}">Acknowledgements</a>
+	</li>
+      </xsl:if>
+      <xsl:if test="frontmatter">
+	<li class='toc'>
+	  <a href="{$library_name}?a=xd&amp;sa=text&amp;d={$docName}.frontmatter&amp;c={$collName}">About this document</a>
+	</li>
+      </xsl:if>
+      <li class='toc'><a href="{$library_name}?a=xd&amp;sa=text&amp;d={$docName}&amp;c={$collName}">Full version</a>
+      </li>
+    </ul>
+    <xsl:apply-templates select="bookbody"><xsl:with-param name="collName" select="$collName"/><xsl:with-param name="docName" select="$docName"/></xsl:apply-templates>
+    <xsl:if test="backmatter">
+      <ul class='toc'>
+	<li class='toc'>
+	<a href="{$library_name}?a=xd&amp;sa=text&amp;d={$docName}.backmatter&amp;c={$collName}">Back matter (may include appendices, index, glossary etc)</a>
+	</li>
+      </ul>
+    </xsl:if>
+  </xsl:template>
+    
+  <xsl:template match="bookbody">
+    <xsl:param name="collName"/>
+    <xsl:param name="docName"/>
+    <ul class="toc">
+      <xsl:apply-templates select="part|chapter">
+	<xsl:with-param name="collName" select="$collName"/>
+	<xsl:with-param name="docName" select="$docName"/>
+      </xsl:apply-templates>
+    </ul>
+  </xsl:template>
+
+  <xsl:template match="part">
+    <xsl:param name="collName"/>
+    <xsl:param name="docName"/>
+    <li class='toc'>
+      <a href="{$library_name}?a=xd&amp;sa=text&amp;c={$collName}&amp;d={$docName}.bookbody.part.{@gs3:id}">Part <xsl:value-of select="position()"/></a>
+      <xsl:if test="chapter">
+	<ul class='toc'>
+	  <xsl:apply-templates select="chapter">
+	  <xsl:with-param name="collName" select="$collName"/>
+	  <xsl:with-param name="docName" select="$docName"/>
+	</xsl:apply-templates>
+	</ul>
+      </xsl:if>
+    </li>
+  </xsl:template>
+
+  <xsl:template match="chapter">
+    <xsl:param name="collName"/>
+    <xsl:param name="docName"/>
+    <li class='toc'>
+      <a href="{$library_name}?a=xd&amp;sa=text&amp;c={$collName}&amp;d={$docName}.bookbody.chapter.{@gs3:id}">
+	<xsl:choose>
+	  <xsl:when test="title">
+	    <xsl:value-of select="title"/>
+	  </xsl:when>
+	  <xsl:when test="chapheader">
+	    <xsl:value-of select="chapheader/chapnum"/>: <xsl:value-of select="chapheader/title"/>
+	  </xsl:when>
+	  <xsl:otherwise>
+	    Chapter <xsl:value-of select="position()"/>
+	  </xsl:otherwise>
+	</xsl:choose>
+      </a>
+    </li>
+  </xsl:template>
+   
+</xsl:stylesheet>
+
+
+
+
+
+
+
Index: /greenstone3/trunk/web/sites/localsite/collect/gberg/transform/produce-toc.xsl
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gberg/transform/produce-toc.xsl	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gberg/transform/produce-toc.xsl	(revision 14125)
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:util="xalan://org.greenstone.gsdl3.util.XSLTUtil"
+  extension-element-prefixes="java util"
+  exclude-result-prefixes="java util">
+  
+  <xsl:output method="xml"/>
+
+  <xsl:strip-space elements='*'/>
+
+  <xsl:template match="gutbook | book | acknowledge | frontmatter | bookbody | backmatter | part | chapter | chapheader "><xsl:copy><xsl:for-each select="@*"><xsl:copy/></xsl:for-each><xsl:apply-templates/></xsl:copy></xsl:template>
+
+  <xsl:template match="title | chapnum">
+    <xsl:copy-of select="."/>
+  </xsl:template>
+
+  <!-- any thing else is ignored -->
+  <xsl:template match="*"></xsl:template>
+  
+</xsl:stylesheet>
Index: /greenstone3/trunk/web/sites/localsite/collect/gs2mgdemo/README
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gs2mgdemo/README	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gs2mgdemo/README	(revision 14125)
@@ -0,0 +1,19 @@
+This collection is based on the original demo collection that comes with 
+Greenstone2. I built the collection using Greenstone2, then copied it 
+across to Greenstone3. I ran the convert_coll_from_gs2.pl Perl script to 
+generate the collectionConfig.xml and buildConfig.xml files, then edited 
+them by hand. I also generated new images for the collection, based on its 
+new name.
+
+The changes I made were:
+
+collectionConfig.xml:
+--------------------
+* More readable XML
+* Changed the English name and description displayItems, and removed the other language items, as they no longer are an accurate translation.
+* added a new displayItem to classifier CL4.
+* changed the image names
+
+buildConfig.xml:
+----------------
+* More readable XML
Index: /greenstone3/trunk/web/sites/localsite/collect/gs2mgdemo/etc/collectionConfig.xml
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gs2mgdemo/etc/collectionConfig.xml	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gs2mgdemo/etc/collectionConfig.xml	(revision 14125)
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CollectionConfig xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+    <metadataList>
+        <metadata lang="en" name="creator">greenstone@cs.waikato.ac.nz</metadata>
+        <metadata lang="en" name="maintainer"/>
+        <metadata lang="en" name="public">true</metadata>
+    </metadataList>
+    <displayItemList>
+        <displayItem assigned="true" lang="en" name="description">This is a demonstration collection for the Greenstone3 digital library software. It contains a small subset (11 books) of the Humanitarian and Development Libraries. It is a Greenstone2 collection, built with MG. The Greenstone2 configuration files have been converted to Greenstone3 equivalents, enabling it to be served using Greenstone3.</displayItem>
+        <displayItem assigned="true" lang="en" name="smallicon">gs2mgdemo_sm.gif</displayItem>
+        <displayItem assigned="true" lang="en" name="icon">gs2mgdemo.gif</displayItem>
+        <displayItem assigned="true" lang="en" name="name">Greenstone2 MG demo collection</displayItem>
+    </displayItemList>
+    <search type="mg">
+        <index name="document:text">
+            <displayItem lang="ru" name="name">ÐÐŸÐ»ÐœÑÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ</displayItem>
+            <displayItem lang="en" name="name">entire documents</displayItem>
+            <displayItem lang="es" name="name">documentos enteros</displayItem>
+            <displayItem lang="fr" name="name">documents entiers</displayItem>
+        </index>
+        <index name="section:Title">
+            <displayItem lang="ru" name="name">ÐÐ°Ð·Ð²Ð°ÐœÐžÑ ÑÐ°Ð·ÐŽÐµÐ»ÐŸÐ²</displayItem>
+            <displayItem lang="en" name="name">section titles</displayItem>
+            <displayItem lang="es" name="name">tÃ­tulos de las secciones</displayItem>
+            <displayItem lang="fr" name="name">titres des sections</displayItem>
+        </index>
+        <index name="section:text">
+            <displayItem lang="ru" name="name">ÐÐ»Ð°Ð²Ñ</displayItem>
+            <displayItem lang="en" name="name">chapters</displayItem>
+            <displayItem lang="es" name="name">capÃ­tulos</displayItem>
+            <displayItem lang="fr" name="name">chapitres</displayItem>
+        </index>
+        <format name="searchType">plain,form</format>
+        <format><gsf:template match="documentNode">                                                                                                                          <td valign="top">                                                                                                                                                                                       <gsf:link type="document">                                                                                                                                                                                                                                                    <gsf:icon type="document"/>                                                                                                                                                                                                                     </gsf:link>                                                                                                                                                        </td>                                                                                                                          <td>                                                                                                                                                                                       <gsf:switch>                                                                                                                                                                                                                                                    <gsf:metadata name="Title" select="ancestors" separator=": "/>                                                                                                                                                                                                                                                    <gsf:when test="exists">                                                                                                                                                                                                                                                                                                                 <gsf:metadata name="Title" select="ancestors" separator=": "/>                                                                                                                                                           :                                                                                                                            </gsf:when>                                                                                                                                                                                                                     </gsf:switch>                                                                                                                                                                                       <gsf:link type="document">                                                                                                                                                                                                                                                    <gsf:metadata name="Title"/>                                                                                                                                                                                                                     </gsf:link>                                                                                                                                                        </td>                                                                                           </gsf:template></format>
+    </search>
+    <import>
+        <pluginList>
+            <plugin name="ZIPPlug"/>
+            <plugin name="GAPlug"/>
+            <plugin name="TEXTPlug"/>
+            <plugin name="HTMLPlug"/>
+            <plugin name="EMAILPlug"/>
+            <plugin name="PDFPlug"/>
+            <plugin name="RTFPlug"/>
+            <plugin name="WordPlug"/>
+            <plugin name="MetadataXMLPlug"/>
+            <plugin name="ArcPlug"/>
+            <plugin name="RecPlug"/>
+        </pluginList>
+    </import>
+    <browse>
+        <classifier name="AZList">
+            <option name="-metadata" value="dls.Subject"/>
+            <format><gsf:template match="classifierNode" mode="horizontal">                                                                  <gsf:link type="horizontal">                                                                                                   <gsf:metadata name="Title"/>                                                                                  </gsf:link>                                                 </gsf:template></format>
+        </classifier>
+        <classifier name="AZCompactList">
+            <option name="-metadata" value="dls.Title"/>
+        </classifier>
+        <format><gsf:template match="documentNode">                                                                                                                          <td valign="top">                                                                                                                                                                                       <gsf:link type="document">                                                                                                                                                                                                                                                    <gsf:icon type="document"/>                                                                                                                                                                                                                     </gsf:link>                                                                                                                                                        </td>                                                                                                                             <td valign="top">                                                                                                                                                                                       <gsf:metadata name="srclink"/>                                                                                                                                                                                       <gsf:choose-metadata>                                                                                                                                                                                                                                                    <gsf:metadata name="thumbicon"/>                                                                                                                                                                                                                                                    <gsf:metadata name="srcicon"/>                                                                                                                                                                                                                     </gsf:choose-metadata>                                                                                                                                                                                       <gsf:metadata name="/srclink"/>                                                                                                                                                        </td>                                                                                                                             <td valign="top">                                                                                                                                                                                           <gsf:choose-metadata>                                                                                                                                                                                                                                                    <gsf:metadata name="dc.Title"/>                                                                                                                                                                                                                                                    <gsf:metadata name="exp.Title"/>                                                                                                                                                                                                                                                    <gsf:metadata name="Title"/>                                                                                                                                                                                                                                                    <gsf:default>                                                                                                                                                           Untitled                                                                                                                            </gsf:default>                                                                                                                                                                                                                     </gsf:choose-metadata>                                                                                                                                                                                           <gsf:switch>                                                                                                                                                                                                                                                    <gsf:metadata name="Source"/>                                                                                                                                                                                                                                                    <gsf:when test="exists">                                                                                                                                                                                                                                                                                                                 <br/>                                                                                                                                                                                                                                                                                                                 <i>                                                                                                                                                                                          (                                                                                                                                                                                          <gsf:metadata name="Source"/>                                                                                                                                                                                          )                                                                                                                                                           </i>                                                                                                                                                                                                                                                                                  </gsf:when>                                                                                                                                                                                                                     </gsf:switch>                                                                                                                                                        </td>                                                                                           </gsf:template>                                                             <gsf:template match="classifierNode">                                                                                                                          <td valign="top">                                                                                                                                                                                       <gsf:link type="classifier">                                                                                                                                                                                                                                                    <gsf:icon type="classifier"/>                                                                                                                                                                                                                     </gsf:link>                                                                                                                                                        </td>                                                                                                                             <td valign="top">                                                                                                                                                                                       <gsf:metadata name="srclink"/>                                                                                                                                                                                       <gsf:choose-metadata>                                                                                                                                                                                                                                                    <gsf:metadata name="thumbicon"/>                                                                                                                                                                                                                                                    <gsf:metadata name="srcicon"/>                                                                                                                                                                                                                     </gsf:choose-metadata>                                                                                                                                                                                       <gsf:metadata name="/srclink"/>                                                                                                                                                        </td>                                                                                                                             <td valign="top">                                                                                                                                                                                           <gsf:choose-metadata>                                                                                                                                                                                                                                                    <gsf:metadata name="dc.Title"/>                                                                                                                                                                                                                                                    <gsf:metadata name="exp.Title"/>                                                                                                                                                                                                                                                    <gsf:metadata name="Title"/>                                                                                                                                                                                                                                                    <gsf:default>                                                                                                                                                           Untitled                                                                                                                            </gsf:default>                                                                                                                                                                                                                     </gsf:choose-metadata>                                                                                                                                                                                           <gsf:switch>                                                                                                                                                                                                                                                    <gsf:metadata name="Source"/>                                                                                                                                                                                                                                                    <gsf:when test="exists">                                                                                                                                                                                                                                                                                                                 <br/>                                                                                                                                                                                                                                                                                                                 <i>                                                                                                                                                                                          (                                                                                                                                                                                          <gsf:metadata name="Source"/>                                                                                                                                                                                          )                                                                                                                                                           </i>                                                                                                                                                                                                                                                                                  </gsf:when>                                                                                                                                                                                                                     </gsf:switch>                                                                                                                                                        </td>                                                                                           </gsf:template>                                                             <gsf:template match="classifierNode" mode="horizontal">                                                                                                                          <gsf:link type="horizontal">                                                                                                                                                                                       <gsf:metadata name="Title"/>                                                                                                                                                        </gsf:link>                                                                                           </gsf:template></format>
+    </browse>
+    <display>
+        <format><gsf:template match="documentcontent">                                                                                                  </gsf:template>                                                                  <gsf:option name="TOC" value="true"/>                                        </format>
+    </display>
+    <replaceListRef id="gs2-standard"/>
+</CollectionConfig>
Index: /greenstone3/trunk/web/sites/localsite/collect/gs2mgdemo/gs2mgdemo.col
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gs2mgdemo/gs2mgdemo.col	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gs2mgdemo/gs2mgdemo.col	(revision 14125)
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE GathererCollection [
+  <!ELEMENT GathererCollection (Argument*, GathererConfig, BuildConfig)>
+  <!ELEMENT GathererConfig    (Arguments*)>
+  <!ELEMENT BuildConfig       (Build, Import)>
+  <!ELEMENT Build             (Arguments*)>
+  <!ELEMENT Import            (Arguments*)>
+  <!ELEMENT Argument          (#PCDATA)>
+  <!ATTLIST Argument
+            name              CDATA #REQUIRED
+				enabled           CDATA "true">
+]>
+<GathererCollection>
+    <Argument name="built">false</Argument>
+    <Argument name="imported">true</Argument>
+    <GathererConfig/>
+    <BuildConfig>
+        <Build>
+            <Argument enabled="false" name="faillog"/>
+            <Argument enabled="false" name="index"/>
+            <Argument enabled="false" name="language"/>
+            <Argument enabled="false" name="maxnumeric">4</Argument>
+            <Argument enabled="false" name="mode">all</Argument>
+            <Argument enabled="false" name="sections_index_document_metadata">never</Argument>
+            <Argument enabled="false" name="verbosity">0</Argument>
+        </Build>
+        <Import>
+            <Argument enabled="false" name="faillog"/>
+            <Argument enabled="false" name="maxdocs">1</Argument>
+            <Argument enabled="false" name="OIDtype">hash</Argument>
+            <Argument enabled="false" name="OIDmetadata">dls.Title</Argument>
+            <Argument enabled="false" name="saveas">GA</Argument>
+            <Argument enabled="false" name="sortmeta">dls.Title</Argument>
+            <Argument enabled="false" name="removeprefix"/>
+            <Argument enabled="false" name="removesuffix"/>
+            <Argument enabled="false" name="groupsize">1</Argument>
+            <Argument enabled="false" name="verbosity">0</Argument>
+        </Import>
+    </BuildConfig>
+</GathererCollection>
Index: /greenstone3/trunk/web/sites/localsite/collect/gs2mgdemo/index/buildConfig.xml
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gs2mgdemo/index/buildConfig.xml	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gs2mgdemo/index/buildConfig.xml	(revision 14125)
@@ -0,0 +1,33 @@
+<buildConfig xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat">
+<metadataList>
+<metadata name="numDocs">11</metadata>
+<metadata name="buildType">mg</metadata>
+</metadataList>
+<serviceRackList>
+<serviceRack name="GS2MGSearch">
+<indexStem name="gs2mgdemo" />
+<indexList>
+<index name="document:text" shortname="dte" />
+<index name="section:Title" shortname="sti" />
+<index name="section:text" shortname="ste" />
+</indexList>
+<defaultIndex shortname="dte" />
+<indexOptionList>
+<indexOption name="stemIndexes" value="3" />
+<indexOption name="maxnumeric" value="4" />
+</indexOptionList>
+<defaultGDBMLevel shortname="Doc" />
+</serviceRack>
+<serviceRack name="GS2MGRetrieve">
+<defaultIndex shortname="dte" />
+<indexStem name="gs2mgdemo" />
+</serviceRack>
+<serviceRack name="GS2Browse">
+<indexStem name="gs2mgdemo" />
+<classifierList>
+<classifier name="CL1" content="dls.Subject" />
+<classifier name="CL2" content="dls.Title" />
+</classifierList>
+</serviceRack>
+</serviceRackList>
+</buildConfig>
Index: /greenstone3/trunk/web/sites/localsite/collect/gs2mgppdemo/README
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gs2mgppdemo/README	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gs2mgppdemo/README	(revision 14125)
@@ -0,0 +1,17 @@
+This collection is based on the original demo collection that comes with 
+Greenstone2. I converted the collect.cfg file so that the collection used MGPP,
+then built the collection using Greenstone2, and copied it 
+across to Greenstone3. I ran the convert_coll_from_gs2.pl Perl script to 
+generate the collectionConfig.xml and buildConfig.xml files, then edited 
+them by hand. I also generated new images for the collection, based on its 
+new name.
+
+The changes I made were:
+
+collectionConfig.xml:
+--------------------
+* More readable XML
+
+buildConfig.xml:
+----------------
+* More readable XML
Index: /greenstone3/trunk/web/sites/localsite/collect/gs2mgppdemo/etc/collectionConfig.xml
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gs2mgppdemo/etc/collectionConfig.xml	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gs2mgppdemo/etc/collectionConfig.xml	(revision 14125)
@@ -0,0 +1,103 @@
+<collectionConfig xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+><metadataList
+><metadata name="creator"
+>greenstone@cs.waikato.ac.nz</metadata
+><metadata name="public"
+>true</metadata
+></metadataList
+><displayItemList
+><displayItem name="description" lang="en"
+>This is a demonstration collection for the Greenstone3 digital library software. It contains a small subset (11 books) of the Humanitarian and Development Libraries. It is a Greenstone2 collection, built with MGPP, which provides form based searching. The Greenstone2 configuration files have been converted to Greenstone3 equivalents, enabling it to be served using Greenstone3.</displayItem
+><displayItem name="smallicon" lang="en"
+>gs2mgppdemo_sm.gif</displayItem
+><displayItem name="icon" lang="en"
+>gs2mgppdemo.gif</displayItem
+><displayItem name="name" lang="en"
+>Greenstone2 MGPP demo collection</displayItem
+></displayItemList
+><search type="mgpp"
+><index name="dls.Organization"
+><displayItem name="name" lang="en"
+>organisations</displayItem
+></index
+><index name="dls.Title"
+><displayItem name="name" lang="en"
+> titles</displayItem
+></index
+><index name="text"
+><displayItem name="name" lang="en"
+>text</displayItem
+></index
+><index name="allfields"
+><displayItem name="name" lang="en"
+>all fields</displayItem
+></index
+><index name="dls.Subject"
+><displayItem name="name" lang="en"
+>subjects</displayItem
+></index
+><level name="document"
+></level
+><level name="section"
+></level
+><defaultLevel name="document"></defaultLevel><format
+><gsf:template match="documentNode"
+><td valign='top'><gsf:link type='document'><gsf:icon type='document'/></gsf:link></td><td><gsf:switch><gsf:metadata name='Title' select='ancestors' separator=': ' /><gsf:when test='exists' ><gsf:metadata name='Title' select='ancestors' separator=': ' />:</gsf:when></gsf:switch><gsf:link type='document'><gsf:metadata name='Title' /></gsf:link></td></gsf:template
+></format
+><indexOption>
+	<option name="accentfold" />
+	<option name="casefold" />
+	<option name="stem" />
+</indexOption>
+</search
+>    <import>
+        <pluginList>
+            <plugin name="GAPlug"/>
+            <plugin name="HTMLPlug">
+                <option name="-description_tags"/>
+            </plugin>
+            <plugin name="MetadataXMLPlug"/>
+            <plugin name="ArcPlug"/>
+            <plugin name="RecPlug"/>
+        </pluginList>
+    </import>
+<browse
+><format
+><gsf:template match="documentNode"
+><td valign="top"><gsf:link type='document'><gsf:icon type='document'/></gsf:link></td> <td valign="top"><gsf:metadata name='srclink' /><gsf:choose-metadata><gsf:metadata name='thumbicon' /><gsf:metadata name='srcicon' /></gsf:choose-metadata><gsf:metadata name='/srclink' /></td> <td valign="top"> <gsf:choose-metadata><gsf:metadata name='dc.Title' /><gsf:metadata name='exp.Title' /><gsf:metadata name='Title' /><gsf:default>Untitled</gsf:default></gsf:choose-metadata> <gsf:switch><gsf:metadata name='Source' /><gsf:when test='exists' ><br /><i>(<gsf:metadata name='Source' />)</i></gsf:when></gsf:switch></td></gsf:template
+><gsf:template match="classifierNode"
+><td valign="top"><gsf:link type='classifier'><gsf:icon type='classifier'/></gsf:link></td> <td valign="top"><gsf:metadata name='srclink' /><gsf:choose-metadata><gsf:metadata name='thumbicon' /><gsf:metadata name='srcicon' /></gsf:choose-metadata><gsf:metadata name='/srclink' /></td> <td valign="top"> <gsf:choose-metadata><gsf:metadata name='dc.Title' /><gsf:metadata name='exp.Title' /><gsf:metadata name='Title' /><gsf:default>Untitled</gsf:default></gsf:choose-metadata> <gsf:switch><gsf:metadata name='Source' /><gsf:when test='exists' ><br /><i>(<gsf:metadata name='Source' />)</i></gsf:when></gsf:switch></td></gsf:template
+><gsf:template match="classifierNode" mode="horizontal"
+><gsf:link type='horizontal'><gsf:metadata name='Title' /></gsf:link></gsf:template
+></format
+>        
+<classifier name="AZList">
+            <option name="-metadata" value="dls.Title"/>
+</classifier>
+<classifier name="Hierarchy">
+            <option name="-metadata" value="dls.Subject"/>
+            <option name="-sort" value="dls.Title"/>
+</classifier>
+        <classifier name="AZCompactList">
+            <option name="-metadata" value="dls.Organization"/>
+            <option name="-sort" value="dls.Title"/>
+            <option name="-mingroup" value="1"/>
+            <option name="-buttonname" value="Organization"/>
+        </classifier>
+        <classifier name="List">
+            <option name="-metadata" value="dls.Keyword"/>
+            <option name="-buttonname" value="Howto"/>
+        <format
+><gsf:template match="documentNode"
+><td><gsf:link type='document'><gsf:metadata name='dls.Keyword' /></gsf:link></td></gsf:template
+><gsf:template match="classifierNode"
+><td><gsf:link type='classifier'><gsf:metadata name='dls.Keyword' /></gsf:link></td></gsf:template
+></format
+></classifier
+></browse
+>    <display>
+        <format><gsf:template match="documentcontent">                                                                                                  </gsf:template>                                                                  <gsf:option name="TOC" value="true"/>                                        </format>
+    </display>
+<replaceListRef id="gs2-standard"
+ /></collectionConfig
+>
Index: /greenstone3/trunk/web/sites/localsite/collect/gs2mgppdemo/gs2mgppdemo.col
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gs2mgppdemo/gs2mgppdemo.col	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gs2mgppdemo/gs2mgppdemo.col	(revision 14125)
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE GathererCollection [
+  <!ELEMENT GathererCollection (Argument*, GathererConfig, BuildConfig)>
+  <!ELEMENT GathererConfig    (Arguments*)>
+  <!ELEMENT BuildConfig       (Build, Import)>
+  <!ELEMENT Build             (Arguments*)>
+  <!ELEMENT Import            (Arguments*)>
+  <!ELEMENT Argument          (#PCDATA)>
+  <!ATTLIST Argument
+            name              CDATA #REQUIRED
+				enabled           CDATA "true">
+]>
+<GathererCollection>
+    <Argument name="built">false</Argument>
+    <Argument name="imported">true</Argument>
+    <GathererConfig/>
+    <BuildConfig>
+        <Build/>
+        <Import/>
+    </BuildConfig>
+</GathererCollection>
Index: /greenstone3/trunk/web/sites/localsite/collect/gs2mgppdemo/index/buildConfig.xml
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/gs2mgppdemo/index/buildConfig.xml	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/gs2mgppdemo/index/buildConfig.xml	(revision 14125)
@@ -0,0 +1,44 @@
+<buildConfig xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat">
+<metadataList>
+<metadata name="numDocs">11</metadata>
+<metadata name="buildType">mgpp</metadata>
+</metadataList>
+<serviceRackList>
+<serviceRack name="GS2MGPPSearch">
+<indexStem name="gs2mgppdemo" />
+<indexList>
+<index name="dls.Organization" shortname="DL" />
+<index name="dls.Title" shortname="DS" />
+<index name="text" shortname="TX" />
+<index name="allfields" shortname="ZZ" />
+<index name="dls.Subject" shortname="DU" />
+</indexList>
+<indexOptionList>
+<indexOption name="stemIndexes" value="7" />
+<indexOption name="maxnumeric" value="4" />
+</indexOptionList>
+<levelList>
+<level name="document" shortname="Doc" />
+</levelList>
+<defaultLevel shortname="Doc" />
+<defaultGDBMLevel shortname="Doc" />
+<searchTypeList>
+<searchType name="plain" />
+<searchType name="form" />
+</searchTypeList>
+</serviceRack>
+<serviceRack name="GS2MGPPRetrieve">
+<indexStem name="gs2mgppdemo" />
+<defaultLevel shortname="Doc" />
+</serviceRack>
+<serviceRack name="GS2Browse">
+<indexStem name="gs2mgppdemo" />
+<classifierList>
+<classifier name="CL1" content="dls.Title" />
+<classifier name="CL2" content="dls.Subject" />
+<classifier name="CL3" content="Organization" />
+<classifier name="CL4" content="Howto" />
+</classifierList>
+</serviceRack>
+</serviceRackList>
+</buildConfig>
Index: /greenstone3/trunk/web/sites/localsite/collect/infomine/README
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/infomine/README	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/infomine/README	(revision 14125)
@@ -0,0 +1,105 @@
+This collection talks to the iVia installation at INFOMINE, Riverside, 
+California. The software should work with any iVia installation. 
+
+Cgi scripts are called to do searching of and retrieval from the database. 
+All three are fairly generic CGI scripts; iVia's "theming" ability is used to
+ get the data back in the format we want-- there is a gsdl3 theme. 
+
+To create a new collection that talks to an iVia database, you need to create 
+the two configuration files, collectionConfig.xml, and buildConfig.xml. 
+The collectionConfig.xml needs to contain any display information for the 
+collection, and any metadata that is available. Also it can contain format 
+information for document display or search result lists if the default is 
+not useful.
+
+The buildConfig.xml file needs to specify the IViaProxy serviceRack 
+class. Inside this element should be the url of the iVia installation that
+you want to connect to. Here is an example:
+
+<buildConfig> 
+  <metadataList/>
+  <serviceRackList>                                                            
+    <serviceRack name="IViaProxy">
+      <iViaServer url="http://infominehelper.ucr.edu"/>
+    </serviceRack>
+  </serviceRackList>
+</buildConfig>
+
+
+The following describes the iVia cgi scripts.
+
+For performing a search:
+************************
+
+  <serverhome>/cgi-bin/canned_search
+
+Parameters:
+  Required parameters: theme=gsdl3&query=xxx
+  Useful parameters: no_of_records_per_page=10&start_page_no=1&fields='kw,su'
+  Other parameters: http://infomine.ucr.edu/help/adders/index.php?section=11
+  Example: http://infomine.ucr.edu/cgi-bin/canned_search?query=tree&
+              theme=gsdl3&no_of_records_per_page=10&start_page_no=1
+
+Fields include Title (ti), Subject (su), Keyword (kw), Author (au), 
+Description (de) and full text (fu). 'all' will search all fields.
+It's possible to do uch more advanced searches including phrase searching 
+and bolean queries.
+
+The canned_search result page will look something like this:
+  Resources: 58
+  Ids:  1015 22128 1730 6020 2981 1014 20147 2097 46569 4360
+
+For getting an HTML representation of a record:
+***********************************************
+
+  <serverhome>/cgi-bin/view_record
+
+Parameters:
+  Required parameters: theme=gsdl3&record_id=x
+  Example: http://infomine.ucr.edu/cgi-bin/view_record?theme=gsdl3&
+                record_id=2097
+
+The result page will be an HTML fragment; specifically, it will be an HTML
+table.  Again, the formatting is quite flexible.  There's one current
+problem: a lot of the data is displayed as hypertext links to new infomine
+searches; This should be changed eventually.
+
+For now, the Greenstone services process the records, replacing infomine 
+links with Greenstone links where possible. 
+
+For getting metadata for a set of records:
+******************************************
+
+  <serverhome>/cgi-bin/view_record_set
+
+Parameters:
+  Required parameters: theme=gsdl3&record_id_list=id1,id2,id3
+  Optional parameter: field_list=f1,f2,f3
+  Example: http://infomine.ucr.edu/cgi-bin/view_record_set?theme=gsdl3&
+                record_id_list=1015,2128,1730&field_list=url,title
+
+The result will look like this:
+
+  Record: 1015
+  url: http://www.fruit.affrc.go.jp/index-e.html
+  title: National Institute of Fruit Tree Science (Japan)
+
+  Record: 2128
+  url: http://www.publish.csiro.au/journals/ajb/
+  title: Australian Journal of Botany
+
+  Record: 1730
+  url: http://usda.mannlib.cornell.edu/reports/erssor/specialty/fts-bb/
+  title: Fruit and Tree Nuts : USDA Economics and Statistics System
+
+There are many different metadata fields that can be requested, including
+keywords, subjects, ivia_description, access, expert_created, foreign_source,
+foreign_id, and so on.  
+
+Note that the metadata always fits on one line (whitespace is explicitly
+normalised to space) to make parsing easier.  Generally, the metadata is
+in ISO-8859-15 format (i.e. ISO-8859-1 plus the Euro currency symbol). 
+Metadata is usually plain text, though the description field may contain
+HTML entities and limited set of HTML elements (bold tags, italic tags,
+links, and a few others).
+
Index: /greenstone3/trunk/web/sites/localsite/collect/infomine/etc/collectionConfig.xml
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/infomine/etc/collectionConfig.xml	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/infomine/etc/collectionConfig.xml	(revision 14125)
@@ -0,0 +1,39 @@
+<collectionConfig xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
+  <metadataList/>
+  <displayItemList>
+    <displayItem name='name' lang=''>Infomine proxy demo</displayItem>
+    <displayItem name='description' lang='en'>&lt;p&gt;This is a demonstration collection that acts as a proxy to the iVia database at &lt;a href="http://infomine.ucr.edu/"&gt;INFOMINE&lt;/a&gt;, Riverside, California. No data is stored locally; instead, the search and retrieval services invoke cgi scripts at infomine to query the database, and retrieve records and metadata.&lt;/p&gt;
+&lt;p&gt;A &lt;a
+    href="sites/localsite/collect/infomine/README"&gt;README&lt;/a&gt; file
+    describes the cgi scripts and how to invoke them. The configuration
+    files for the collection are very basic, and merely specify display 
+    information for the collection, and specify the IViaProxy service
+    rack. The collection configuration can be seen &lt;a
+    href="sites/localsite/collect/infomine/etc/collectionConfig.xml"&gt;here&lt;/a&gt;,
+    and the building configuration file can be seen &lt;a
+    href="sites/localsite/collect/infomine/index/buildConfig.xml"&gt;here&lt;/a&gt;.
+       You may need to "view page source" to see the raw XML. &lt;/p&gt; 
+</displayItem>    
+    <displayItem name='icon' lang='en'>infomine.gif</displayItem>  
+    <displayItem name='smallicon' lang='en'>infomine.gif</displayItem>  
+  </displayItemList>  
+  <search>
+    <format>
+      <gsf:template match="documentNode">
+	<td valign='top'><gsf:link><gsf:icon/></gsf:link></td><td>
+	  <table><tr><td><a><xsl:attribute name='href'><gsf:metadata name="url"/></xsl:attribute><b><gsf:metadata name="title"/></b></a></td></tr>
+	    <tr><td><gsf:metadata name="ivia_description"/></td></tr>
+	    <tr><td><b><gsf:metadata name="url"/></b></td></tr>
+	    <tr><td>[<gsf:link>View Full Record</gsf:link>]</td></tr></table>
+	</td>
+      </gsf:template>
+    </format>
+  </search>
+  <display>
+  <format>
+  <gsf:template name="documentHeading">
+  <gsf:metadata name="title"/>
+</gsf:template>	
+</format>
+</display>
+</collectionConfig>
Index: /greenstone3/trunk/web/sites/localsite/collect/infomine/index/buildConfig.xml
===================================================================
--- /greenstone3/trunk/web/sites/localsite/collect/infomine/index/buildConfig.xml	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/collect/infomine/index/buildConfig.xml	(revision 14125)
@@ -0,0 +1,11 @@
+<buildConfig> 
+  <metadataList/>
+  <serviceRackList>                                                            
+    <serviceRack name="IViaSearch">
+    <iViaServer url="http://infominehelper.ucr.edu"/>
+    </serviceRack>
+    <serviceRack name="IViaRetrieve">
+    <iViaServer url="http://infominehelper.ucr.edu"/>
+    </serviceRack>
+  </serviceRackList>
+</buildConfig>
Index: /greenstone3/trunk/web/sites/localsite/siteConfig.xml
===================================================================
--- /greenstone3/trunk/web/sites/localsite/siteConfig.xml	(revision 14125)
+++ /greenstone3/trunk/web/sites/localsite/siteConfig.xml	(revision 14125)
@@ -0,0 +1,35 @@
+<siteConfig xmlns:gsf='http://www.greenstone.org/greenstone3/schema/ConfigFormat' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
+  <siteList/>
+  <serviceRackList>
+    <!-- uncomment to provide the GATE tagging service -->
+    <!--<serviceRack name="GATEServices"/>-->
+    <serviceRack name="BerryBasket"/>
+    <serviceRack name="CrossCollectionSearch">
+      <format>
+	<!-- this format is used for the search results -->
+	<gsf:template match="documentNode">
+	  <td><a><xsl:attribute name='href'>?a=d&amp;c=<xsl:value-of select='@collection'/>&amp;d=<xsl:value-of select='@nodeID'/><xsl:if test="@nodeType='leaf'">&amp;sib=1</xsl:if>&amp;dt=<xsl:value-of select='@docType'/>&amp;p.a=q&amp;&amp;p.s=TextQuery&amp;p.c=</xsl:attribute><gsf:icon/></a></td>
+	  <td>[<a href='?a=p&amp;sa=about&amp;c={@collection}'><xsl:value-of select='@collection'/></a>]</td>
+	  <td><gsf:metadata name='Title'/></td>
+	</gsf:template>
+      </format>
+    </serviceRack>
+  </serviceRackList>
+  <serviceClusterList/>
+  <!-- this is a global replace list for all collections. At this stage it only applies to greenstone 2 collections. It will attempt to resolve most of the common macros that appear in metadata. You can add more items here if you want them to apply to all collections. To turn this on/off for a particular collection, add <replaceListRef id='xx'/> into the collectionConfig for each set that you want to use -->
+  <replaceList  id="gs2-standard">
+    <replace macro="_iconpdf_" scope="metadata" text="&lt;img src='interfaces/default/images/ipdf.gif' border='0'/&gt;" resolve="false"/>
+    <replace macro="_icondoc_" scope="metadata" text="&lt;img src='interfaces/default/images/imsword.gif' border='0'/&gt;" resolve="false"/>
+    <replace macro="_iconps_" scope="metadata" text="&lt;img src='interfaces/default/images/ips.gif' border='0'/&gt;" resolve="false"/>
+     <replace macro="_iconrtf_" scope="metadata" text="&lt;img src='interfaces/default/images/irtf.gif' border='0'/&gt;" resolve="false"/>
+    <replace macro="\[archivedir\]" scope="all" metadata="archivedir" resolve="false"/>
+    <replace macro="\[assocfilepath\]" scope="metadata" metadata="assocfilepath" resolve="false"/>
+    <replace macro="\[Image\]" scope="metadata" metadata="Image" resolve="false"/>
+    <replace macro="\[Thumb\]" scope="metadata" metadata="Thumb" resolve="false"/>
+    <!-- _httpsite_ and _clustername_ are macros that are defined in the java code -->
+    <replace macro="_httpcollection_" scope="metadata" text="_httpsite_/collect/_clustername_" resolve="true"/>
+    <replace macro="_httpprefix_" scope="metadata" text="_httpsite_" resolve="true"/>
+    <replace macro="_httpdocimg_" scope="text" text="_httpsite_/collect/_clustername_/index/assoc/[archivedir]/" resolve="true"/>
+    <replace macro="\[collection\]" scope="all" text="_clustername_" resolve="true"/>
+  </replaceList>
+</siteConfig>
Index: /greenstone3/trunk/web/xmlextras.js
===================================================================
--- /greenstone3/trunk/web/xmlextras.js	(revision 14125)
+++ /greenstone3/trunk/web/xmlextras.js	(revision 14125)
@@ -0,0 +1,149 @@
+//<script>
+//////////////////
+// Helper Stuff //
+//////////////////
+
+// used to find the Automation server name
+function getDomDocumentPrefix() {
+	if (getDomDocumentPrefix.prefix)
+		return getDomDocumentPrefix.prefix;
+	
+	var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];
+	var o;
+	for (var i = 0; i < prefixes.length; i++) {
+		try {
+			// try to create the objects
+			o = new ActiveXObject(prefixes[i] + ".DomDocument");
+			return getDomDocumentPrefix.prefix = prefixes[i];
+		}
+		catch (ex) {};
+	}
+	
+	throw new Error("Could not find an installed XML parser");
+}
+
+function getXmlHttpPrefix() {
+	if (getXmlHttpPrefix.prefix)
+		return getXmlHttpPrefix.prefix;
+	
+	var prefixes = ["MSXML2", "Microsoft", "MSXML", "MSXML3"];
+	var o;
+	for (var i = 0; i < prefixes.length; i++) {
+		try {
+			// try to create the objects
+			o = new ActiveXObject(prefixes[i] + ".XmlHttp");
+			return getXmlHttpPrefix.prefix = prefixes[i];
+		}
+		catch (ex) {};
+	}
+	
+	throw new Error("Could not find an installed XML parser");
+}
+
+//////////////////////////
+// Start the Real stuff //
+//////////////////////////
+
+
+// XmlHttp factory
+function XmlHttp() {}
+
+XmlHttp.create = function () {
+	try {
+		if (window.XMLHttpRequest) {
+			var req = new XMLHttpRequest();
+			
+			// some versions of Moz do not support the readyState property
+			// and the onreadystate event so we patch it!
+			if (req.readyState == null) {
+				req.readyState = 1;
+				req.addEventListener("load", function () {
+					req.readyState = 4;
+					if (typeof req.onreadystatechange == "function")
+						req.onreadystatechange();
+				}, false);
+			}
+			
+			return req;
+		}
+		if (window.ActiveXObject) {
+			return new ActiveXObject(getXmlHttpPrefix() + ".XmlHttp");
+		}
+	}
+	catch (ex) {}
+	// fell through
+	throw new Error("Your browser does not support XmlHttp objects");
+};
+
+// XmlDocument factory
+function XmlDocument() {}
+
+XmlDocument.create = function () {
+	try {
+		// DOM2
+		if (document.implementation && document.implementation.createDocument) {
+			var doc = document.implementation.createDocument("", "", null);
+			
+			// some versions of Moz do not support the readyState property
+			// and the onreadystate event so we patch it!
+			if (doc.readyState == null) {
+				doc.readyState = 1;
+				doc.addEventListener("load", function () {
+					doc.readyState = 4;
+					if (typeof doc.onreadystatechange == "function")
+						doc.onreadystatechange();
+				}, false);
+			}
+			
+			return doc;
+		}
+		if (window.ActiveXObject)
+			return new ActiveXObject(getDomDocumentPrefix() + ".DomDocument");
+	}
+	catch (ex) {}
+	throw new Error("Your browser does not support XmlDocument objects");
+};
+
+// Create the loadXML method and xml getter for Mozilla
+if (window.DOMParser &&
+	window.XMLSerializer &&
+	window.Node && Node.prototype && Node.prototype.__defineGetter__) {
+
+	// XMLDocument did not extend the Document interface in some versions
+	// of Mozilla. Extend both!
+	//XMLDocument.prototype.loadXML = 
+	Document.prototype.loadXML = function (s) {
+		
+		// parse the string to a new doc	
+		var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
+		
+		// remove all initial children
+		while (this.hasChildNodes())
+			this.removeChild(this.lastChild);
+			
+		// insert and import nodes
+		for (var i = 0; i < doc2.childNodes.length; i++) {
+			this.appendChild(this.importNode(doc2.childNodes[i], true));
+		}
+	};
+	
+	
+	/*
+	 * xml getter
+	 *
+	 * This serializes the DOM tree to an XML String
+	 *
+	 * Usage: var sXml = oNode.xml
+	 *
+	 */
+	// XMLDocument did not extend the Document interface in some versions
+	// of Mozilla. Extend both!
+	/*
+	XMLDocument.prototype.__defineGetter__("xml", function () {
+		return (new XMLSerializer()).serializeToString(this);
+	});
+	*/
+	Document.prototype.__defineGetter__("xml", function () {
+		return (new XMLSerializer()).serializeToString(this);
+	});
+}
